为什么这段代码不起作用?如果字符串是数字,我想返回Bool。
isNumber = do
n <- getLine
let val = case reads n of
((v,_):_) -> True
_ -> False
答案 0 :(得分: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 }
因为您的函数尚未返回值。修复:
isNumber = do
n <- getLine
let val = case reads n of
((v,_):_) -> True
_ -> False
return val
现在它在语法上是正确的,但它有一个类型错误:
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)
为什么呢?因为read
超载了。所以编译器不知道你想要读什么。在这种情况下,您正在尝试读取数字。比方说,Integer
:
isNumber :: IO Bool
isNumber = do
n <- getLine
let val = case (reads :: ReadS Integer) n of
((v,_):_) -> True
_ -> False
return val
尽管如此,它并不是真正的惯用语。让我们将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)
测试:
*Main> getNumber
123
Just 123
*Main> getNumber
dons
Nothing
因此我们已经清理了解析,并将IO从解析中分离出来,这意味着您可以单独测试解析器,并添加类型信息来记录您的设计。
答案 1 :(得分:0)
添加return val
或只写return $ case ...
。 do ...
中的最后一个语句必须是表达式。在您的特定情况下,它必须是IO Bool
类型的表达式,因此您需要使用return
函数将值提升到IO monad中。您还需要明确指定v
的类型(您可能需要ScopedTypeVariables
GHC扩展名。)
编写一个单独的String -> Bool
类纯函数也是一个好主意,并在不纯的IO代码中使用它。