我编写了下面的简单程序,确信它会吸收我击中的所有击键,并且当我击中 q 时,它会将之前的键打印为单个字符串。
import System.IO
main = do
hSetBuffering stdin NoBuffering
hSetEcho stdin False
x <- takeWhile (/= 'q') <$> sequence (repeat getChar)
print x
但事实并非如此。
这并不是说按键没有被读取,因为当我将最长的行更改为
时很明显 x <- takeWhile (/= 'q') <$> sequence (repeat (getChar >>= \c -> print c >> return c))
当我输入字符时,它会一一打印出来;但 q 不会导致循环退出。
我的理解是,
sequence
并不懒惰,因为它会在getChar
有机会开始其工作之前尝试运行无限的takeWhile
操作列表。
如果是这样的话,我还有什么其他选择?
如果上面的代码片段的意图很明确,我可以补充一点,在实际应用程序中
getChar
将与 do
es c <- getChar
的函数交换,然后对其进行处理。
您可以考虑为此目的采取一些辅助措施:
getInput :: Char -> IO Char
getInput previous = do
c <- getChar
if c == 'q' then return previous else getInput c
这将使您能够获得
x
喜欢
x <- getInput ' '
或使用其他适当的默认值代替
' '
。
如果您确实想要单行代码,您始终可以使用
fix
将任何递归操作转换为 lambda 表达式。
首先,然后
import Data.Function
然后
x <-
(fix $ \rec previous -> getChar >>= \c -> if c == 'q' then return previous else rec c) ' '