2016-09-29 200 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

感謝 - 它不是真正的'有用'的情況,更多的是試圖掌握什麼函數/應用函子能做什麼以及它們可以用在哪裏...... –