如何在不求助于(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