[英]can't build lambdabot with ghc-7.8 (@ haskell-src-exts)
[英]ambiguity error with `reads` in ghc-7.8
我正在測試使用GHC-7.8.2 在48小時內為自己編寫一個Scheme的代碼,這給我一個關於模糊性的錯誤,我不記得在以前版本的GHC中遇到過。 摘錄如下,問題行標記為:
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| String String
| Bool Bool
unpackNum :: LispVal -> Integer
unpackNum (Number n) = n
unpackNum (String n) = let parsed = reads n in --problem line
if null parsed
then 0
else fst $ parsed !! 0
unpackNum (List [n]) = unpackNum n
unpackNum _ = 0
,錯誤說:
No instance for (Read a0) arising from a use of ¡®parsed¡¯
The type variable ¡®a0¡¯ is ambiguous
Note: there are several potential instances:
instance Read a => Read (Control.Applicative.ZipList a)
-- Defined in ¡®Control.Applicative¡¯
instance Read () -- Defined in ¡®GHC.Read¡¯
instance (Read a, Read b) => Read (a, b) -- Defined in ¡®GHC.Read¡¯
...plus 26 others
如果我將問題行更改為
unpackNum (String n) = let parsed = reads n ::[(Integer,String)] in
一切正常。
我不明白為什么GHC未能推斷從簽名讀取類型unpackNum
。 有人可以解釋是什么引發了錯誤?
(
- 編輯 -
只是一些后續行動。 據我所知,函數類型unpackNum :: LispVal -> Integer
以及unpackNum :: LispVal -> Integer
fst $ parsed !! 0
的事實fst $ parsed !! 0
fst $ parsed !! 0
是它的返回值告訴parsed
類型為[(Integer,b)]
,並且從type ReadS a = String -> [(a,String)]
, parsed
應該是[(a, String)]
。 這兩種類型不應該統一到[(Integer, String)]
並修復parsed
的類型嗎?
有人可以解釋為什么NoMonomorphismRestriction
會打破上述推理嗎?
- EDIT2 -
從答案中,我可以理解NoMonomorphismRestriction
如何在這里引起問題。 但是,我不明白的事實是,這種“兩種類型的相同表達”行為如何與Haskell中的懶惰一致。 在parsed
或reads n
的示例reads n
是一個塊中的相同表達式,應僅評估一次。 它怎么能有型a
評估,第一時間Integer
第二次?
)
謝謝,
如果NoMonomorphismRestriction
處於活動狀態,則會觸發此操作; 其中,順便說一下,自7.8以來GHCi默認情況就是這樣(見發行說明,第1.5.2.3節) 。
如果禁用單態限制,則parsed
的定義將獲得多態類型,即
parsed :: Read a => [(a, String)]
然后在null parsed
的第一次使用沒有足夠的上下文信息來解析a
是什么。
這恰好是單形態限制實際上有所好處的少數情況之一。 因為對於多態類型,即使兩個使用站點都有足夠的類型信息來解析類約束,實際的解析也會發生兩次。
最好的解決方案仍然是使用acomar的答案中建議的模式匹配。
這些類型應該統一,但不存在NoMonomorphismRestriction
(如@FedorGogolev和@kosmikus的評論中所述)。 但是,以下更慣用的方法在任何情況下都不需要類型注釋:
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| String String
| Bool Bool
unpackNum :: LispVal -> Integer
unpackNum (Number n) = n
unpackNum (String n) = case reads n of
[] -> 0
((x, _):xs) -> x
unpackNum (List [n]) = unpackNum n
unpackNum _ = 0
歸結為null
是一個函數,而case
是直接語法。
null :: [a] -> Bool
因此,啟用了-XNoMonomorphismRestriction,在提供參數時,這將保持多態。 該函數不以任何方式限制參數類型,因此編譯器無法確定reads
的返回類型,從而導致錯誤。 在函數調用的站點,類型是不明確的。 在case
語句的case
,編譯器具有要使用的整個表達式,因此模式匹配以優化reads
的返回類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.