【问题标题】:Custom while loop in Haskell prints a statement twiceHaskell中的自定义while循环两次打印一条语句
【发布时间】:2014-01-09 16:33:32
【问题描述】:

我是 Haskell 的新手,一直在努力更好地理解 IO monad(在玩了一段时间的纯函数之后)。

我正在关注IO monad上的教程

其中一个练习是制作 while 函数。他们没有显示示例,因此您无法检查答案。

这是我的:

while :: IO Bool -> IO ()
while action = do p <- action
                  if p then putStrLn "You win!" >> return ()
                       else putStrLn "Nope. Try again!" >> while action


main = do putStrLn "Come and guess the letter!"
          while (constAskForC)
          where constAskForC = do c <- getChar
                                  return $ c == 'c'

现在,我的问题是,如果您输入了错误的字符(几乎是一个不是 'c' 的字符),那么字符串 "Nope. Try again!"被打印两次到 StdOut。为什么是这样?这是正在运行的程序:

Come and guess the letter!


"Nope. Try again!"

"Nope. Try again!"
d
"Nope. Try again!"
"Nope. Try again!"

"Nope. Try again!"

"Nope. Try again!"
a
"Nope. Try again!"
"Nope. Try again!"
d
"Nope. Try again!"
"Nope. Try again!"
f
"Nope. Try again!"
"Nope. Try again!"
a
"Nope. Try again!"
"Nope. Try again!"
s
"Nope. Try again!"
"Nope. Try again!"

如果您只是按回车键(不输入字符),那么它只会打印一次。谁能向我解释我做错了什么?

谢谢。

【问题讨论】:

  • 我最初的猜测是缓冲模式。在导入System.IO 后尝试hSetBuffering stdout LineBuffering,看看是否能解决您的问题。
  • 您输入一个字母并按回车键。一个字母就是一个字符。 Enter 是另一个字符。这给出了两个字符,数一下;)

标签: haskell io stdout monads


【解决方案1】:

问题出在constAskForC 函数中。您使用getChar,但只会读取一个字符。所以你读c,读完c,你会得到行尾字符(\n)。实在没办法获取单个字符,但是可以获取一整行只取第一个字符:

main = do putStrLn "Come and guess the letter!"
          while (constAskForC)
  where constAskForC = do c <- getLine
                          return $ case c of
                            [] ->     False -- There was no input              
                            'c':[] -> True -- The first letter was a c, and nothing else was entered
                            _      -> False -- Otherwise, the result is False

关于您的代码的另一个小注释:putStrLn "You win!" &gt;&gt; return ()putStrLn "You win!" 相同

【讨论】:

  • 啊,忘记了 是一个字符。谢谢!
【解决方案2】:

这里的问题是getChar 命令的行为与正常的交互 编译程序的缓冲行为,即使用行缓冲。

getChar 命令只使用一个字符。特别是,点击回车会自行创建一个换行符。

但是,使用行缓冲,在您输入完整行之前实际上不会有任何输入到达。 所以如果你把一个字符和回车键交错,就会一次生成两个字符,导致输出奇怪。

您可以通过添加该行来解决此问题

import System.IO

开头再添加语句

hSetBuffering stdin NoBuffering

main 程序。或者,使用默认使用 NoBuffering 的 GHCi。

【讨论】:

    【解决方案3】:

    当您键入一个字符并按 Enter 键时,这实际上是两个字符(可打印字符加上一个换行符)。您可能想改用getLine

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-12
      • 2021-08-07
      • 1970-01-01
      • 2021-01-01
      • 2021-06-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多