我有这种类型:
data Move a t = Emove a a
| Move a t a
我想把它变成一个仿函数:
instance Functor Move where
fmap f (Emove x y) = Emove (f x) (f y)
fmap f (Move x c y) = Move (f x) c (f y)
但由于此类型的错误类型,因此无法编译。有人可以帮我解决这个问题吗?如何向此实例提供类型t
?
答案 0 :(得分:3)
如果将类型变量的顺序交换为Move
:
data Move t a = Emove a a | Move a t a
然后您可以将仿函数定义为
instance Functor (Move t) where
fmap f (Emove x y) = Emove (f x) (f y)
fmap f (Move x c y) = Move (f x) c (f y)
任何属于仿函数的类型都必须具有* -> *
种,这就是它的定义方式。由于您的类型为* -> * -> *
,因此您必须在仿函数下使其中一个类型变量保持不变(或者使用bifunctor,其中明确的目的是在两个类型变量上都有一个仿函数)。由于您希望a
更改而不是t
,因此Haskell要求a
类型变量排在最后,它只是语法的工作方式。与Either
类型相似,仿函数实例为Functor (Either a)
,但这是一个非常随意的定义,它只会使用Right
构造函数更改值,而它可以使用Left
构造函数等价地定义值。数学上的含义是相同的,但为了保持一致性,Haskell通过语法强制执行,可以通过仿函数更改的类型变量是最后一个类型变量。
答案 1 :(得分:3)
您可以考虑改为Bifunctor
:
instance Bifunctor Move where
bimap f g (EMove a a') = EMove (f a) (f a')
bimap f g (Move a t a') = Move (f a) (g t) (f a')
然后,操作first f
将执行您希望fmap f
执行的操作。
答案 2 :(得分:2)
简而言之:你做不到。 Functor
仅在一种类型上进行参数化。
因此,您只能将其作为第二种类型Functor
的实例,部分应用:
instance Functor (Move a) where
您可以交换类型变量,使其在您的定义中进行参数化。