我刚开始使用Haskell,这让我很困惑。我之前做了Java和Python,对我来说更有意义。
我正在尝试获取用户输入,检查它是否有效,如果没有:打印错误并再次获取输入;如果有效:从中生成一个布尔值。
更确切地说,我想要一个是/否输入,其中'y'将产生True,'n'将产生False,而任何其他输入将在命令行中输出一条消息并要求输入y / n试。
E.g:
Continue? y/n:
> assd
Invalid input.
Continue? y/n:
> y
(something happens)
Continue? y/n:
> n
(Close program)
以farmiliar格式编写,这样的函数:
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后,一切都评估为一个值,这对我来说没有意义。 “做”评估的是什么? 还有什么缩进预期?这似乎是随机的。 我知道函数必须求值为我的布尔值,使用这个“do”操作似乎不可能。但是,我如何将某些内容打印到控制台并仍然使其成为评估为True或False的表达式的一部分?
感谢您的帮助。
(顺便问一下。互联网上有任何活跃的haskell论坛吗?我找不到任何= /)
答案 0 :(得分:22)
由于您的函数需要执行IO,因此它必须在IO
monad中返回一个值,因此其类型必须为yesno :: IO Bool
,True
和False
需要通过return
将值提升到monad中。您还需要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 ()