2012-04-20 43 views
4

這是一個初學者的問題,但我無法在任何地方識別出任何答案。
下面的代碼:在類型類型的默認值中輸入註釋會導致「無法推論」類型的錯誤

class A a where 
    foo :: a 
class A a => B a where 
    bar :: a 
    bar = (foo :: a) 

未能在GHC編譯,並顯示錯誤消息:

Could not deduce (A a1) arising from a use of `foo' 
from the context (B a) 
    bound by the class declaration for `B' 
... 

GHC似乎不相信所有的一個在類型類B的定義是相同的。任何人都可以請解釋究竟是哪一種推理?

刪除第5行類型標註避免課程的問題,但我還是想明白是怎麼回事...

回答

11

你確實應該擺脫類型的註釋。類型變量不在Haskell範圍內,所以(foo :: a)。被解釋爲「具有foo對於任何類型a產生類型a的值」,其不能如foo那樣完成,將只產生類中屬於A類的值。

換句話說,你的B聲明等效於

class A a => B a where 
    bar :: a 
    bar = (foo :: c) 

也就是說,有您的使用類型變量a並在聲明中的其他用途之間沒有任何聯繫。

刪除明確標註解決您的問題:現在

class A a => B a where 
    bar :: a 
    bar = foo 

,編譯器可以計算出你想調用foo,即,對於你在bar簽名寫的類型a什麼類型和出現在類聲明的頭部。

格拉斯哥Haskell編譯器(GHC)附帶允許範圍類型變量的擴展。啓用該擴展,您的片段類型檢查就像你原先預期:

{-# LANGUAGE ScopedTypeVariables #-} 
class A a where 
    foo :: a 
class A a => B a where 
    bar :: a 
    bar = (foo :: a) 
+0

非常感謝! XScopedTypeVariables的文檔正是我所需要的。 – bklin 2012-04-20 10:16:02

+0

@bklin:如果你認爲它足夠全面,你應該接受他的答案;) – 2012-04-20 11:56:55

2
Prelude> :set -XScopedTypeVariables 
Prelude> :{ 
Prelude| class A a where 
Prelude| foo :: a 
Prelude| class A a => B a where 
Prelude| bar :: a 
Prelude| bar = (foo :: a) 
Prelude| :} 
Prelude> :t bar 
bar :: B a => a 
Prelude> 

但dblhelox說,這是不是真的有必要在這裏使用範圍的類型變量。

相關問題