![](/img/trans.png)
[英]How to combine Megaparsec with Text.Read (derived Read instance)
[英]Understanding readMaybe (Text.Read)
我目前正在學習Haskell並對Joachim Breitner的在線課程CIS194中的這個例子有疑問:
import Text.Read
main = putStrLn "Hello World. Please enter a number:" >>
getLine >>= \s ->
case readMaybe s of -- why not `readMaybe s :: Maybe Int` ?!
Just n -> let m = n + 1 in
putStrLn (show m)
Nothing -> putStrLn "That’s not a number! Try again"
代碼完全符合預期,即如果輸入是整數則返回整數+1,並返回“那不是數字!再試一次”( 例如,如果輸入是Double
)。 我不明白為什么readMaybe s
只返回Just n
如果n
是Int
類型。 readMaybe
的類型是readMaybe :: Read a => String -> Maybe a
因此我認為只有在讀取行時才會起作用:
case readMaybe s :: Maybe Int of
事實上,如果我只是在ghci中提示> readMaybe "3"
,它返回Nothing
,而> readMaybe "3" :: Maybe Int
返回Just 3
。
總而言之,我的問題如下:現在編譯器如何在沒有使用:: Maybe Int
情況下將s
解析為Int
而不是其他東西( 例如 Double
)? 為什么每次都沒有返回Nothing
?
我希望我的問題很清楚,非常感謝你的幫助。
TL; DR: readMaybe s
上下文告訴我們它是一個Num a => Maybe a
,默認使它成為一個Maybe Integer
。
我們必須查看使用readMaybe
結果確定其類型的所有位置。
我們有
Nothing
,這並沒有告訴我們aynthing約a
Just n
, n
在上下文中使用m = n + 1
。 由於m = n + 1
,我們現在知道n
的類型必須是Num
的實例,因為(+) :: Num a => a -> a -> a
和1 :: Num a => a
。 此時類型不明確,因此default
:
4.3.4模糊類型和重載數值運算的默認值
topdecl -> default (type1 , ... , typen) (n>=0)
Haskell樣式重載所固有的問題是模糊類型的可能性。 例如,使用第10章中定義的read和show函數,並假設只有Int和Bool是Read和Show的成員,那么表達式
let x = read "..." in show x -- invalid
是不明確的,因為顯示和閱讀的類型,
show :: forall a. Show a =>a ->String read :: forall a. Read a =>String ->a
可以通過在兩種情況下將a實例化為Int或Bool來滿足。 這種表達被認為是錯誤的,是一種靜態錯誤。
我們說表達式e有一個模糊的類型,如果,在它的類型forall u。 cx => t,u中有一個類型變量u,它出現在cx中但不出現在t中。 這些類型無效。
Haskell報告中定義的default
是default (Integer, Double)
,例如GHC首先嘗試Integer
,如果不起作用,則嘗試使用Double
。
由於Integer
是上下文m = n + 1
的有效類型,因此我們有m :: Integer
,因此n :: Integer
,最后是readMaybe s :: Maybe Integer
。
如果你想要禁用default
,使用default ()
,你會受到模糊類型錯誤的歡迎,就像你期望的那樣。
由於類型推斷是如何工作的,確實存在一些潛在的魔力。
這是一個更簡單的例子,在GHCi中運行:
> print (1 :: Integer)
1
> print (1 :: Float)
1.0
Prelude> print 1
1
在最后一行中, 1
是類型Num a => a
的多態值,即任何數字類型內的值,如Integer
和Float
。 如果我們在Integer
類型中考慮該值,我們將其打印為“1”。 如果我們將它視為Float
,我們將其打印為“1.0”。 其他數字類型甚至可能具有不同的打印格式。
不過,最后一行中的GHCi決定1
是Integer
。 為什么?
好吧,事實證明代碼含糊不清:畢竟1
可以用不同的方式打印! 由於模糊性,Haskell在這種情況下會引發錯誤。 但是,它為數字類型(那些包含Num
)提供了一個例外,以便更方便編程。 具體地說,當數字類型沒有由代碼精確確定時,Haskell使用其默認規則 ,該規則指定應該使用哪些數字類型。
此外,傳播類型。 如果我們評估
case readMaybe s of
Just x -> let z = x + length ['a','z']
in ...
GHC知道length
返回Int
。 此外, (+)
僅對相同類型的參數進行操作,因此x
也必須是Int
。 這反過來意味着調用readMaybe s
必須返回Maybe Int
。 因此,正確的Read
例如Int
選擇秒。
請注意類型推理引擎如何向后傳播此信息,以便程序員不必添加可從其余代碼推斷出的類型注釋。 它在Haskell中經常發生。
一個人可以一直是明確的,如同
readMaybe s :: Maybe Int
-- or, with extensions on, one can mention the variable part of the type, only
readMaybe s @ Int
如果您願意,可以隨意添加此類注釋。 有時,它們會使代碼更具可讀性,因為它們記錄了您的意圖。 無論誰讀取代碼,都可以在不查看上下文的情況下立即找到正在使用的Read
實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.