2016-09-29 76 views
0

我已经得到了以下数据类型:函数声明有多种类型?

data Users id height weight = User id height weight 

instance Functor Users where 
fmap f (User id height weight) = User(f id height weight) 

然而,这不会编译?

当我使用一个类型与一个单一的参数,如它正常工作:

data Users id = User id 
instance Functor Users where 
fmap f (User id) = User (f id) 

为什么不是我的第一个例子中的工作?

+0

第二个例子并没有做你认为的事情 - 你需要对'fmap'进行缩进才能使它成为实例的一部分。第一个示例省略了错误,它告诉你这个问题(n.b.这是一个类型问题,函子实例是'* - > *'类型的)。 –

+0

'然而这不会编译?'编译器错误是什么? –

回答

6

每种类型和类型的构造函数都有一种。简单像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好像它可以正常工作,并且不需要将功能映射到此处:您需要多长时间一次以相同的方式修改身高,体重和年龄?

+0

那么无论如何将函子应用到我的第一个例子中? –

+0

查看我最近的更新:你认为什么功能适用于用户的身高,体重,*和*年龄? – chepner

+0

感谢 - 它不是真正的'有用'的情况,更多的是试图掌握什么函数/应用函子能做什么以及它们可以用在哪里...... –