2012-05-04 77 views
3

我正在使用Haskell的FunctionalDependencies-Extension和MultiParamTypeClasses。我定義如下:帶有Haskell函數依賴關係的模糊變量

class Add a b c | a b -> c where 
    (~+) :: a -> b -> c 
    (~-) :: a -> b -> c 
    neg :: a -> a 
    zero :: a 

工作正常(我與詮釋情況下試圖和Double具有能夠增加INT和雙打沒有明確轉換的終極目標)。

當我嘗試定義默認實現NEG或(〜 - ),像這樣:

class Add ... 
    ... 
    neg n = zero ~- n 

GHCI(7.0.4)告訴我下面的:

Ambiguous type variables `a0', `b0', `c0' in the constraint: 
    (Add a0 b0 c0) arising from a use of `zero' 
Probable fix: add a type signature that fixes these type variable(s) 
In the first argument of `(~-)', namely `zero' 
In the expression: zero ~- n 
In an equation for `neg': neg n = zero ~- n 

Ambiguous type variable `a0' in the constraint: 
    (Add a0 a a) arising from a use of `~-' 
Probable fix: add a type signature that fixes these type variable(s) 
In the expression: zero ~- n 
In an equation for `neg': neg n = zero ~- n 

我覺得我做的瞭解這裏的問題。 GHC不知道哪個零使用,因爲它可以是任何零產生任何東西,然後反饋給我們只知道的~-,它有一個a它是正確的參數,併產生一個a

所以,我怎麼可以指定它應該從非常相同的實例零,即我怎麼能表達的東西,如:

neg n = (zero :: Add a b c) ~- n 

我覺得abc這裏的abc形成周圍的類,但任何ab和c,所以我怎麼能表達一個類型,它是對本地類型變量的引用?

回答

6

negzero出成只使用一種類型的超:

class Zero a where 
    neg :: a -> a 
    zero :: a 

class Zero a => Add a b c | a b -> c where 
    (~+) :: a -> b -> c 
    (~-) :: a -> b -> c 

的一點是,你的方式,zero :: Int可能是zeroAdd Int Int IntzeroAdd Int Double Double和無論是從默認實現,實例聲明還是普通代碼中引用它,都無法消除這兩者之間的歧義。

(你可以反對的zeroAdd Int Int IntzeroAdd Int Double Double將具有相同的價值,但是編譯器不知道別人是不會在不同的模塊定義Add Int Char Bool,給zero不同的值在那裏。)

通過將類型分成兩部分,我們消除了歧義。

3

您不能將zero函數表示爲Add類的一部分。必須在類的每個函數的類型聲明中遇到類聲明中的所有類型變量;否則,Haskell將無法決定使用哪種類型的實例,因爲它的約束太少。

換句話說,zero不是您正在建模的類的屬性。你基本上是這樣說的:「對於a,b,c的任何三種類型,a類型必須存在零值」,這是沒有意義的;你可以選擇任何bc它會解決問題,因此bc是完全無法使用的,所以如果你有一個Add Int Int IntAdd Int (Maybe String) Boat,Haskell不知道哪個實例更喜歡。您需要否定和「zeroness」的財產分成類型的一個單獨的類(ES):

class Invertible a where 
    invert :: a -> a 

neg :: Invertible a => a -> a 
neg = invert 

class Zero a where 
    zero :: a 

class Add a b c | a b -> c where 
    (~+) :: a -> b -> c 
    (~-) :: a -> b -> c 

我不明白你爲什麼會那麼即使需要AddInvertibleZero限制;你總是可以在不知道零值的情況下添加數字,你不可以嗎?爲什麼要將neg作爲~+的要求表達;有些數字應該是可加的,而不會被否定(例如自然數)?只要保持課堂關注不同。