每种类型和类型的构造函数都有一种。简单像Int
有种*
。你的单参数类型构造函数Users
有种类* -> *
;它需要一种类型并返回一个新类型。您的Users
的第一个示例具有种类* -> * -> * -> *
;需要三个类型并返回一个新的类型。
Functor
只适用于类型为* -> *
的构造函数。这使您可以为第二个Users
类型构造函数定义一个Functor
实例,但不是第一个。
想一想你的第一次尝试:数据构造函数Users
需要三个参数,但是你的定义fmap
试图用一个返回值f来调用它。你可以做Users
仿函数,只要你愿意让所有三个字段相同的类型:
data Users a = Users a a a
instance Functor Users where
fmap f (Users a b c) = Users (f a) (f b) (f c)
在理论上,你可以定义一个类Trifunctor
(有一个Bifunctor
类可用):
class Trifunctor f where
trimap :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> f a1 a2 a3 -> f b1 b2 b3
data Users a b c = Users a b c
instance Trifunctor Users where
trimap f g h (Users a b c) = Users (f a) (g b) (h c)
但它是有争议的,这将是多么有用。 Functor
对通用容器很有用,因为它们具有广泛的用途。另一方面,Users
看起来非常具体。您通常不需要您定义它的灵活性; data User = User Int Int Int
好像它可以正常工作,并且不需要将功能映射到此处:您需要多长时间一次以相同的方式修改身高,体重和年龄?
第二个例子并没有做你认为的事情 - 你需要对'fmap'进行缩进才能使它成为实例的一部分。第一个示例省略了错误,它告诉你这个问题(n.b.这是一个类型问题,函子实例是'* - > *'类型的)。 –
'然而这不会编译?'编译器错误是什么? –