2015-11-07 44 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