如何在不求助于(a, a)的情况下使Functor成为newtype

基本上我希望它像这样工作:

instance Functor (a, a) where
  fmap f (x, y) = (f x, f y)

但这当然不是表达它的合法方法:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `(a, a)' has kind `*'
In the instance declaration for `Functor (a, a)'

我真正想要的是这样的类型级别的函数:\a -> (a, a)(无效的语法)。那么是类型别名吗?
type V2 a = (a, a)
instance Functor V2 where
    fmap f (x, y) = (f x, f y)

我认为这会起作用,但是不会。首先,我收到此投诉:
Illegal instance declaration for `Functor V2'
(All instance types must be of the form (T t1 ... tn)
 where T is not a synonym.
 Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Functor V2'

如果我遵循建议并添加了TypeSynonymInstances扩展名,则会收到新错误:
Type synonym `V2' should have 1 argument, but has been given 0
In the instance declaration for `Functor V2'

好吧,这就是重点! V2具有一种* -> *,这是Functor实例所需的。好吧,好的,我可以这样使用newtype:
newtype V2 a = V2 (a, a)
instance Functor V2 where
  fmap f (V2 (x, y)) = V2 (f x, f y)

但是现在我必须在我的整个代码中自由地撒上V2,而不是仅仅能够处理简单的元组,这使将其设置为Functor的目的不合时宜;到那时,我不妨自己编写函数vmap :: (a -> b) -> (a, a) -> (b, b)

那么有什么办法可以很好地做到这一点,即没有newtype吗?

最佳答案

正如其他人所指出的,如果不诉诸新类型或数据声明,就无法做到这一点。但是,您看过Control.Arrow吗?其中许多功能对于元组非常有用,例如:

vmap :: (a -> b) -> (a,a) -> (b,b)
vmap f = f *** f

10-06 05:13