2013-01-04 54 views
3

有了函數依賴,我可以聲明Foo類:MultiParamTypeClasses,FunctionalDependencies,並呼籲曖昧功能

class Foo a b c | a -> b where 
    foo1 :: a -> b -> c 
    foo2 :: a -> c 

,當我打電話foo2,一切工作正常。由於依賴關係,編譯器知道使用哪個實例。

但如果我刪除的依賴創造Foo'

class Foo' a b c where 
    foo1' :: a -> b -> c 
    foo2' :: a -> c 

一切仍然編譯罰款,但現在每當我試圖打電話foo2' GHC拋出有關不能夠解決,因爲b使用的情況下錯誤是含糊不清的。

是否有可能無誤地致電foo2'?如果是這樣,怎麼樣?如果沒有,爲什麼它不會產生編譯錯誤?

+0

也不應該編譯,類型foo1'的'和'foo2'意味着'a'的不同種類。你的意思是'a - > b - > c'和'a - > c'? –

+0

@DanielFischer哎呀!你是對的。現在已經修復了。 –

+5

'b'不能從'foo2''到達,因此只有在有直接指定實例的情況下才能確定實例。這可能是一些'ConstraintKinds'巫術,我不知道,但我懷疑它。那麼,不,你永遠不會打電話給'foo2'。爲什麼它不會產生編譯錯誤,我不確定,但我認爲這是編譯器不能證明你永遠無法明確地調用'foo2'。 –

回答

3

在這種情況下不可能調用foo2',因爲正如丹尼爾菲捨爾所言,無法確定使用哪個實例。例如,如果您有:

instance Foo' Int Int Int where 
    foo2' x = x 

instance Foo' Int Bool Int where 
    foo2' x = x + 1 

這兩個foo2' S的具有相同類型的簽名,所以沒有辦法確定調用哪一個。

解決此問題的常用方法是使用代理:

data Proxy a = Proxy 

class Foo'' a b c = where 
    foo2'' :: Proxy b -> a -> c 

你使用像這樣選擇哪一個實例:

foo'' (Proxy :: Proxy Bool) 42 
+1

謝謝。我真的希望ghc會說'Foo2'不能編譯,因爲它的代碼永遠不能運行。好吧。 –