誰能解釋這個錯誤:(構造函數預期)爲什麼構造預計在實例定義在Haskell
語法錯誤的情況下頭部
class Nullable v where
default_val :: v
instance Num a => Nullable a where -- error reported here
default_val = 0::a
感謝
誰能解釋這個錯誤:(構造函數預期)爲什麼構造預計在實例定義在Haskell
語法錯誤的情況下頭部
class Nullable v where
default_val :: v
instance Num a => Nullable a where -- error reported here
default_val = 0::a
感謝
其次,不寫形式
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。有一個真正的誘惑,只要翻轉GHC告訴你的語言標誌。閱讀@ ezyang的Type Technology Tree後,我發現自己能夠做出更好的決定:http://blog.ezyang.com/2011/03/type-tech-tree/ – acfoltzer
有在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
,這在這裏沒有任何意義。
對於':: a'的顯式類型,您可以使用範圍類型變量擴展。 –
這是否適用於實例?我沒有在GHC文檔中看到它(也許我正在尋找錯誤的地方)並嘗試使用'forall'語法似乎不起作用。 – Dan
它適合我。 –
討論
您的代碼是無效的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提供了這裏的擴展是FlexibleInstances和UndecidableInstances。
2)您在您的實例中明確給default_val
一個類型。這完全是不必要的,但如果你堅持,那麼這也有一個名爲ScopedTypeVariables的擴展名。
需要可以啓用或者在一個文件通過文件的基礎上短期
的擴展使用language pragma:
{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-}
或者在任ghc
或ghci
的命令行(其中實際上只是一個包裝ghc
):
ghci -XFLexibleInstances -XUnderstandMyIntent
再次,許多擴展是以GHC爲中心的。你的代碼永遠不會在任何其他Haskell編譯器上運行,或者我的名字不是John Meacham。
還有另一種解決方案:這裏所描述的約束家庭:
class Expr sem where
constraint Pre sem a
constant :: Pre sem a => a -> sem a
add :: Pre sem a => sem a -> sem a -> sem a
instance Expr E where
constraint Pre E a = Num a
...
它說,它是在GHC HEAD可用或GHC 7.4(釋放時)。
我不能重現這個錯誤 - 我得到一個非法的實例聲明錯誤,而不是語法錯誤。 –
@Daniel:這個錯誤出現在擁抱中。 – sdcvvc