簡體   English   中英

了解readMaybe(Text.Read)

[英]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如果nInt類型。 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 ,這並沒有告訴我們aynthinga
  • Just nn在上下文中使用m = n + 1

由於m = n + 1 ,我們現在知道n的類型必須是Num的實例,因為(+) :: Num a => a -> a -> a1 :: 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報告中定義的defaultdefault (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的多態值,即任何數字類型內的值,如IntegerFloat 如果我們在Integer類型中考慮該值,我們將其打印為“1”。 如果我們將它視為Float ,我們將其打印為“1.0”。 其他數字類型甚至可能具有不同的打印格式。

不過,最后一行中的GHCi決定1Integer 為什么?

好吧,事實證明代碼含糊不清:畢竟1可以用不同的方式打印! 由於模糊性,Haskell在這種情況下會引發錯誤。 但是,它為數字類型(那些包含Num )提供了一個例外,以便更方便編程。 具體地說,當數字類型沒有由代碼精確確定時,Haskell使用其默認規則 ,該規則指定應該使用哪些數字類型。

如果需要, GHC可以在發生違約時發出警告

此外,傳播類型。 如果我們評估

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.

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