Во-первых, у вас есть синтаксическая ошибка:
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
Итак, мы очистили синтаксический анализ, иотделил ввод-вывод от парсинга, что означает, что вы можете тестировать свой анализатор изолированно, и добавил информацию о типе для документирования вашего дизайна.