簡體   English   中英

ghc-7.8中“讀取”的模糊性錯誤

[英]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中的懶惰一致。 parsedreads 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM