2015-11-07 74 views
0

我正在嘗試編寫將提示用戶輸入浮點數的代碼,並將繼續這樣做,直到輸入有效的浮點數爲止。從命令行中讀取字符串util可以將「讀取」爲浮點數

我已經嘗試以下方法:

getFloat :: Float 
getFloat = do 
    input <- getLine 
    case (readMaybe input :: Maybe Float) of Just f -> f 
              Nothing -> do getFloat 

但我發現了以下錯誤:

Main.hs:41:5: 
    Couldn't match type `IO b0' with `Float' 
    Expected type: IO String -> (String -> IO b0) -> Float 
     Actual type: IO String -> (String -> IO b0) -> IO b0 
    In a stmt of a 'do' block: input <- getLine 
    In the expression: 
     do { input <- getLine; 
      case (readMaybe input :: Maybe Float) of { 
      Just f -> f 
      Nothing -> do { ... } } } 
    In an equation for `getFloat': 
     getFloat 
      = do { input <- getLine; 
       case (readMaybe input :: Maybe Float) of { 
        Just f -> f 
        Nothing -> ... } } 

Main.hs:42:56: 
    Couldn't match expected type `IO b0' with actual type `Float' 
    In the expression: f 
    In a case alternative: Just f -> f 

Main.hs:43:60: 
    Couldn't match expected type `IO b0' with actual type `Float' 
    In a stmt of a 'do' block: getFloat 
    In the expression: do { getFloat } 

我是初學者會很感激,如果有人能說明什麼我在這裏想念嗎?

+0

看看'getLine'的類型。它是'字符串'嗎? –

回答

1
getFloat :: Float 

這說明getFloatFloat類型的常量,這是不是你想要的。

getFloat :: IO Float 

這代替指出getFloat是製造Float一個IO動作。

修正此問題後,您需要在f前添加return,因爲@ErikR已經解釋過。返回將純浮點值f轉換爲產生它的IO動作,而不實際執行任何IO。

最後,您不需要最後do getFLoat中的dodo語法對於對IO操作進行排序很有用:如果您只有一個,則它是多餘的。

+0

所以沒有辦法從一個IO的函數中產生一個'Float'?而且我會一直被迫拖拽那個IO Float直到我用'<-'? –

+0

@HarryM簡單地說,是的。主要思想是,如果一個函數執行某個IO,這個_將被反映在它的類型上。爲了方便起見,有些助手可以使用標準函數來處理IO。例如。 'cos getFloat'是一個類型錯誤,'do f < - getFloat; return(cosf)'確定但詳細,'cos <$> getFloat'是等價的,簡潔得多。嘗試閱讀這些快捷方式的monad/applicative教程。 – chi

2

對於Just Case,請使用-> return f而不是-> f

然後只刪除getFloat的類型簽名。編譯完成後,讓ghci告訴你getFloat的類型簽名是什麼。

完整代碼:

getFloat = do 
    input <- getLine 
    case (readMaybe input :: Maybe Float) of Just f -> return f 
              Nothing -> do getFloat 

更新

你可能會感興趣的環路的這種高度多態性的版本:

{-# LANGUAGE NoMonomorphismRestriction #-} 
import Text.Read 

getItem = do 
    input <- getLine 
    case readMaybe input of 
    Nothing -> getItem 
    Just x -> return x 

我特意寫getItem沒有類型簽名 - 這是GHC可以推斷併爲您填寫的內容。我還使用了NoMonomorphismRestriction編譯指示,以便getItem保持多態。

想法是getItem可以用於任何可以讀取的類型 - Floats,Doubles,Strings等。readMaybe使用的類型可以由調用者以各種方式控制。下面是一些例子:

main = do 
    f1 <- getItem 
    f2 <- getItem 
    let r = f1 + f2 :: Float 
    print r 

通過迫使r是Float類型,f1f2也必須是浮動的,因此getItem將嘗試解析浮動。

這裏是另一種方式來影響readMaybe使用類型:

main = do 
    f <- getItem :: IO Float 
    i <- getItem :: IO Int 
    print $ f^i -- compute f raised to the i-th power