Подтвердить что ты не робот

Написание циклов для интерактивного ввода-вывода: проблемы с do-notation и layout

Я только что начал Haskell, и это полностью смущает меня. Я делал Java и Python, перед которым было намного больше смысла для меня.

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

Чтобы быть более точным, мне нужен вход yes/no, где "y" будет выдавать True, "n" будет выдавать False, а любой другой вход будет печатать сообщение в командной строке и запрашивать ввод y/n еще раз.

например:.

Continue? y/n:
> assd
Invalid input.
Continue? y/n:
> y
(something happens)
Continue? y/n:
> n
(Close program)

Записывая его в семейном формате, выполните следующие действия:

boolean inputBool() {
    while(True) {
       str = input("Continue? y/n: ");
       if (str == "y") {
           return True;
       } else if (str == "n") {
           return False;
       } else {
           print("Invalid input");
       }
}

--main program--

while(inputBool()) {
    doSomething();
}

Поскольку я только начал haskell (сегодня на самом деле), у меня нет большой идеи, что я могу или не могу сделать. Я думал о чем-то подобном:

yesno :: Bool
yesno = do
        putStr "Continue? y/n: " 
        str <- readLn
        if (str == "y") then True else (
            if (str == "n") then False else (
                do
                putStrLn "Invalid input."
                yesno
            )    
        )

Это не работает по многим причинам. Моя основная проблема заключается в том, что я не знаю, что это делает. Я просто прочитал его, когда он нуждается в операциях io, и каким-то образом выполняет следующие выражения. Что не имеет смысла для меня после прочтения, что в haskell все оценивает значение. Что делает "делать"? Кроме того, какой отступ ожидается? Кажется, это случайный случай. Я знаю, что функция должна оценивать мое логическое значение, которое не представляется возможным при использовании этой операции "делать". Но тогда как я что-то печатаю на консоли и все еще делаю это частью выражения, которое оценивается как True или False?

Спасибо за любую помощь.

(Кстати, есть ли в Интернете активные форумы haskell? Я не нашел ни одного =/)

4b9b3361

Ответ 1

Поскольку ваша функция должна выполнять IO, она должна возвращать значение в монаде IO, поэтому ее тип должен быть yesno :: IO Bool, а значения True и False должны быть подняты в монаду на return. Вам также нужно getLine вместо readLn, так как вам нужна необработанная строка, а не разобранное значение (которое имеет потенциал для ошибки синтаксического анализа). Наконец, вам нужно hFlush stdout перед вызовом getLine, в противном случае приглашение все равно будет сидеть в буфере, ожидающем новой строки (и для этого требуется, чтобы вы импортировали System.IO).

Я ввел строку приглашения в аргумент, поэтому вы можете использовать эту функцию, чтобы задать все вопросы о да/нет:

import System.IO

yesno :: String -> IO Bool
yesno prompt = do
          putStr $ prompt ++ " y/n: "
          hFlush stdout
          str <- getLine
          case str of
            "y" -> return True
            "n" -> return False
            _   -> do
              putStrLn "Invalid input."
              yesno prompt

Затем вы можете вызвать свою функцию из цикла взаимодействия:

main :: IO ()
main = do
         fun <- yesno "Is Haskell fun?"
         if fun
          then putStrLn "rock on"
          else putStrLn "read more tutorials"
         continue <- yesno "Continue?"
         if continue then main else return ()