Haskell - цикл, возвращающий введенное пользователем целое число - PullRequest
0 голосов
/ 07 октября 2018

Я хочу написать функцию, которая при вызове будет постоянно запрашивать ввод данных пользователем, пока ввод не будет прочитан как целое число (в этот момент целое число возвращается в возможный блок do, где функция была вызвана впервое место)

Мой код здесь:

lp_reqInt = 
  do
    input1 <- getLine
    if ((readMaybe input1 :: Maybe Int) == Nothing)
      then do 
             putStrLn "(integer input required, please try again)"
             lp_reqInt 
      else let output = fromMaybe (-666) (readMaybe input1 :: Maybe Int)
    return output

Попытка скомпилировать это дает подозрительно простую ошибку parse error (possibly incorrect indentation or mismatched brackets) для последней строки.(Символы отступа не использовались во всем файле)

Как мне изменить код, чтобы он имел намеченное поведение?Это вообще возможно?

Ответы [ 2 ]

0 голосов
/ 07 октября 2018

В другом ответе обсуждается, что было не так, и минимальное исправление.В дополнение к минимальной вещи, которая заставит вас двигаться дальше с кодом, я подумал, что было бы также интересно показать идиоматическое исправление, а именно использование сопоставления с шаблоном вместо if.Итак:

lp_reqInt :: IO Int
lp_reqInt = do
  input1 <- getLine
  case readMaybe input1 of
    Nothing -> do
      putStrLn "(integer input required, please try again)"
      lp_reqInt
    Just n -> return n

Это не требует использования странного отступления -666 в fromMaybe, что приятно.Использование сопоставления с шаблоном вместо (==) также имеет более тонкое преимущество: ему не требуется, чтобы базовый тип имел экземпляр Eq.Для Int есть один, поэтому в этом коде нет никаких преимуществ, но в других ситуациях это может иметь большее значение.Я также поднял сигнатуру типа на верхний уровень; см. Здесь для дальнейшего обсуждения этой идиомы.

0 голосов
/ 07 октября 2018

Вы, похоже, немного не понимаете, как работает do -обозначение.

Я дам вам «правильную» версию, и мы можем отработать это:

lp_reqInt = do
    input1 <- getLine
    let maybeInput = readMaybe input1 :: Maybe Int
    if maybeInput == Nothing
      then do putStrLn "(integer input required, please try again)"
              lp_reqInt 
      else return $ (\(Just x) -> x) maybeInput

Примечаниеlet -общение наверху там.Я могу сделать let -состояние вместо let - in -статации здесь, потому что оно находится на верхнем уровне do -блока.Когда вы написали let output = fromMaybe (...), он не был на верхнем уровне do -блока, который был во второй части if -статации, следовательно, он не будет работать.

Вы былиполучаю ошибку разбора именно по этой причине: GHC ожидал сопровождающего in!

...