Haskell 使(a,a)成为函子

Haskell 使(a,a)成为函子,haskell,types,functor,typeclass,Haskell,Types,Functor,Typeclass,如何使(a,a)成为函子,而不使用新类型 基本上,我希望它能像这样工作: instance Functor (a, a) where fmap f (x, y) = (f x, f y) newtype V2 a = V2 (a, a) instance Functor V2 where fmap f (V2 (x, y)) = V2 (f x, f y) 但这当然不是一种合法的表达方式: Kind mis-match The first argument of `Functor'

如何使
(a,a)
成为
函子
,而不使用
新类型

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

instance Functor (a, a) where
  fmap f (x, y) = (f x, f y)
newtype V2 a = V2 (a, a)
instance Functor V2 where
  fmap f (V2 (x, y)) = V2 (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
具有类
*->*
,这是
函子
实例所需的。好的,我可以用一个
newtype
如下:

instance Functor (a, a) where
  fmap f (x, y) = (f x, f y)
newtype V2 a = V2 (a, a)
instance Functor V2 where
  fmap f (V2 (x, y)) = V2 (f x, f y)
但是现在我必须在我的代码中自由地散布
V2
s,而不是仅仅能够处理简单的元组,这有点挫败了将它变成
函子的意义;在这一点上,我还可以创建自己的函数
vmap::(a->b)->(a,a)->(b,b)

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

您可以声明

instance Functor ((,) a) where
  ...
但是,这并不约束成对的第一个元素,
fmap
只作用于第二个元素

问题在于元组不强制两个元素类型之间的关系

如果您不想要
newtype
装饰器,您可以制作自己的新类型:

data Pair a = P a a

instance Functor Pair where
  ...

它比元组周围的
newtype
更容易使用。

正如其他人所说,如果不使用newtype或数据声明,就无法做到这一点。但是,您是否查看了
控件.Arrow
?其中许多函数对于元组非常有用,例如:

vmap :: (a -> b) -> (a,a) -> (b,b)
vmap f = f *** f
使用,可以为失效符号定义
函子
类型类(
type~>type
而不是
type->type

这将自动为您提供一个
Prelude.Functor
实例

newtype f $ a = App (Apply f a)

instance Functor' f => Functor (($) f) where
  fmap :: (a -> a') -> (f $ a -> f $ a')
  fmap f (App fa) = App (fmap' @f f fa) 

我不想要一个只作用于元组的一个元素的函子,我想要一个作用于第一个和第二个元素的
(a,a)
(因为它们具有相同的类型)的函子。我试图避免创建新的数据类型。@pelotom,不可能。Functor接受一个数据构造函数参数,
*->*
(a,a)
不是其中之一。你必须使用
newtype
data
@luqui我想你的意思是他们需要一个类型构造函数?这正是我所担心的。。。但是我看不出为什么类型别名不起作用。@pelotom,这很难解释。尝试编写一个可以处理类型同义词实例的类型推断器。这很难,如果可能的话。
实例函子((,)a)
已经在
控制中了。Monad.Instances
@但我不需要“超级函子能力”,它只是稍微方便,看起来应该是可能的,如果不是,我很好奇为什么。@pelotom我同意它似乎应该是可能的,虽然看起来不是。我只是想花点时间站在我的讲台上,宣扬根据你的问题定制表达结构的好处,而不是重载元组。@pelotom:你要找的东西通常被称为“类型级lambdas”;正如你所注意到的,哈斯凯尔没有。有一些相关信息。@DanBurton:我不是OP,但例如,元组的Functor/可遍历实例可以方便地用于(比如,如果您的函数知道低维,并且不想使用列表/向量)。在我看来,这就是解决办法。更好的办法是
vmap=join(***)