读取字符串并测试它是否为数字

0 io parsing haskell

为什么这段代码不起作用?如果string是一个数字,我想返回Bool.

isNumber = do
    n <- getLine
    let val = case reads n of
                ((v,_):_) -> True
                _ -> False
Run Code Online (Sandbox Code Playgroud)

Don*_*art 16

首先,您有语法错误:

A.hs:3:5:
    The last statement in a 'do' construct must be an expression:
    let val
          = case reads n of {
              ((v, _) : _) -> True
              _ -> False }
Run Code Online (Sandbox Code Playgroud)

因为您的函数尚未返回值.修复:

isNumber = do
    n <- getLine
    let val = case reads n of
                ((v,_):_) -> True
                _         -> False
    return val
Run Code Online (Sandbox Code Playgroud)

现在它在语法上是正确的,但它有一个类型错误:

A.hs:3:20:
    Ambiguous type variable `a0' in the constraint:
      (Read a0) arising from a use of `reads'
    Probable fix: add a type signature that fixes these type variable(s)
Run Code Online (Sandbox Code Playgroud)

为什么?因为read超载了.所以编译器不知道你要读什么.在这种情况下,您正在尝试读取数字.让我们说,一个Integer:

isNumber :: IO Bool
isNumber = do
    n <- getLine
    let val = case (reads :: ReadS Integer) n of
                ((v,_):_) -> True
                _         -> False
    return val
Run Code Online (Sandbox Code Playgroud)

不过,它并不是真正的惯用语.让我们将IO与纯代码分开,并实际返回解析后的数字,如果成功的话:

readNumber :: String -> Maybe Integer
readNumber s = case reads s of
            ((v,_):_) -> Just v
            _         -> Nothing

getNumber :: IO (Maybe Integer)
getNumber = do
    s <- getLine
    return (readNumber s)
Run Code Online (Sandbox Code Playgroud)

测试:

*Main> getNumber 
123
Just 123
*Main> getNumber 
dons
Nothing
Run Code Online (Sandbox Code Playgroud)

因此,我们已经清理了解析,并从解析中分离了IO,这意味着您可以单独测试解析器,并添加类型信息来记录您的设计.

  • 但是如果由于某种原因你不想这样做,那么`isNumber`的最后一个版本确实可以完全按照你想要的那样做.这只是丑陋的代码. (3认同)
  • 我的帖子的目的是向您展示如何将问题分解为三个部分,然后您可以将它们组合成一个功能*正确地完成工作*.你的单个函数只是这三个独立函数的*composition*:`getLine`,`readNumber`和`isJust`.像这样分段构建代码只是很好的开发实践. (2认同)