2011-09-23 48 views
1

誰能解釋這個錯誤:(構造函數預期)爲什麼構造預計在實例定義在Haskell

語法錯誤的情況下頭部

class Nullable v where 
    default_val :: v 


instance Num a => Nullable a where -- error reported here 
    default_val = 0::a 

感謝

+0

我不能重現這個錯誤 - 我得到一個非法的實例聲明錯誤,而不是語法錯誤。 –

+0

@Daniel:這個錯誤出現在擁抱中。 – sdcvvc

回答

8

首先,hackage has you covered

其次,不寫形式

instance OtherClass a => Class a where 

的情況下,像你想他們不工作。 (YMMV和GHC以外的編譯器,但我看不出這是一個好主意)。想必你的意圖是創建多個實例,是這樣的:

instance Num a => Nullable a where -- error reported here 
    default_val = 0::a 

instance Bounded a => Nullable a where 
    default_val = minBound 

你能想到的類型類的約束作爲一個額外的參數傳遞給函數,就像這樣:

instance Num a => Nullable a where 
    default_val = NumDict a -> 0::a 

instance Bounded a => Nullable a where 
    default_val = BoundedDict a -> minBound 

然後GHC實際看到這些類像這樣的例子:

instance Nullable a where 
    default_val = NumDict a -> 0::a 

instance Nullable a where 
    default_val = BoundedDict a -> minBound 

現在,哪個實例應該由編譯器選擇?有兩個實例聲稱對所有類型都有效。所以有一個編譯器錯誤。

這是一個問題,即使你有一個基於類的實例。假設你有這些情況:

instance Num a => Nullable a where 
    default_val = 0::a 

instance Nullable String where 
    default_val = "" 

instance Nullable BS.ByteString where 
    default_val = BS.empty 

第一仍然被認爲是適用於所有類型,因此GHC說,它需要OverlappingInstances擴展使用它們。這並非完全邪惡。但是,當您嘗試使用此功能時,不久之後ghc將需要另一個分機,IncoherentInstances

很多人都不敢使用UndecidableInstances,但這種恐懼是錯位的。 UndecidableInstances可能發生的最糟糕的情況是編譯不會終止(但通常是這樣)。 IncoherentInstances是應該激發恐懼的擴展,因爲它會給你的代碼帶來厄運。如果GHC說你必須啓用IncoherentInstances,這意味着你需要改變你的代碼。

TL;博士

不要寫形式

instance OtherClass a => Class a where 

他們不這樣做你想要什麼的實例。

+1

+1。有一個真正的誘惑,只要翻轉GHC告訴你的語言標誌。閱讀@ ezyang的Type Technology Tree後,我發現自己能夠做出更好的決定:http://blog.ezyang.com/2011/03/type-tech-tree/ – acfoltzer

1

有在Haskell一個規則,約束必須比實例本身「小」。我不完全理解背後的理論上的理由,但作爲一個實際問題,你可以用newtype來解決它。

newtype N a = N a 

instance Num a => Nullable (N a) where 
    default_val = N 0 

GHC還有一個選項來禁用這些規則中的一部分。請參閱http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html

另請注意,您不能將::a放在那裏。它並沒有在實例聲明中引用相同的a,但被認爲是通用的a,這在這裏沒有任何意義。

+0

對於':: a'的顯式類型,您可以使用範圍類型變量擴展。 –

+0

這是否適用於實例?我沒有在GHC文檔中看到它(也許我正在尋找錯誤的地方)並嘗試使用'forall'語法似乎不起作用。 – Dan

+0

它適合我。 –

1

討論

您的代碼是無效的Haskell。不要誤會我的意思 - 它是Haskell社區常見的形式,可以由GHC編譯,但我強烈建議您不要將「Haskell」與「Haskell以及GHC可提供的所有擴展」混爲一談。

1)您正在使用另一個類型類作爲約束實例化一個類型類,並且沒有類型構造函數。 2010年哈斯克爾,你必須有一個類型構造:

The general form of the corresponding instance declaration is: instance cx′ => C (T u1 … uk) where { d } where k ≥ 0. The type (T u1 … uk) must take the form of a type constructor T applied to simple type variables u1, … uk; furthermore, T must not be a type synonym, and the ui must all be distinct.

GHC提供了這裏的擴展是FlexibleInstancesUndecidableInstances

2)您在您的實例中明確給default_val一個類型。這完全是不必要的,但如果你堅持,那麼這也有一個名爲ScopedTypeVariables的擴展名。

需要可以啓用或者在一個文件通過文件的基礎上短期

的擴展使用language pragma

{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-} 

或者在任ghcghci的命令行(其中實際上只是一個包裝ghc):

ghci -XFLexibleInstances -XUnderstandMyIntent 

再次,許多擴展是以GHC爲中心的。你的代碼永遠不會在任何其他Haskell編譯器上運行,或者我的名字不是John Meacham。

相關問題