使用kind * - > * - > *一个仿函数创建数据类型

时间:2015-10-29 19:00:27

标签: haskell

我有这种类型:

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

3 个答案:

答案 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

您可以交换类型变量,使其在您的定义中进行参数化。