Чтение строки и проверка, если это число - PullRequest
0 голосов
/ 21 мая 2011

Почему этот код не работает?Я хотел бы вернуть Bool, если строка является числом.

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

Ответы [ 2 ]

16 голосов
/ 21 мая 2011

Во-первых, у вас есть синтаксическая ошибка:

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

Итак, мы очистили синтаксический анализ, иотделил ввод-вывод от парсинга, что означает, что вы можете тестировать свой анализатор изолированно, и добавил информацию о типе для документирования вашего дизайна.

0 голосов
/ 21 мая 2011

Добавить return val или просто написать return $ case ....Последний оператор в do ... должен быть выражением.В вашем конкретном случае это должно быть выражение типа IO Bool, поэтому вам нужно поднять значение в монаду ввода-вывода с помощью функции return.Вам также нужно явно указать тип для v (для этого вам, вероятно, понадобится расширение ScopedTypeVariables GHC.)

Также неплохо написать отдельную чистую функцию типа String -> Bool и использоватьэто в нечистом коде IO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...