我正在使用interact
逐步处理一些用户输入(具体来说,它是国际象棋程序)。但是,我还没有找到一种方法来处理用户可能想要摆脱循环并从头开始匹配国际象棋的情况。
当我在ghci中执行正常程序时,按Ctrl-C
将不会退出整个ghci,但只会停止程序本身并允许我继续执行其他一些程序。但是,如果我在控制台中按Ctrl-C
并生效interact
功能,则会显示以下消息:
^CInterrupted.
*Main>
<stdin>: hGetChar: illegal operation (handle is closed)
然后我必须重新启动ghci。
我还想过捕获特殊的用户输入,例如“退出”,但是,由于interact
的类型是interact :: (String -> String) -> IO ()
,输入必须通过键入的函数(String -> String)
首先,我还没有找到一种方法让该函数通知主IO它应该退出。
我应该如何突破interact
?或者interact
不打算以这种方式使用,我应该编写自定义IO函数吗?
答案 0 :(得分:6)
我该如何突破
interact
?
你做不到。您可以将interact f
视为getContents >>= putStrLn . f
。 getContents
将关闭stdin
上的句柄。任何有关阅读的进一步操作都将失败。
文字字符^ D显示在终端
中
这是readline的一个问题。 GHCi将stdin
的缓冲方法从LineBuffer
更改为NoBuffering
以最佳地使用readline。如果您想使用interact
退出^D
,则需要更改缓冲方法:
ghci> import System.IO
ghci> hGetBuffering stdin
NoBuffering
ghci> hSetBuffering stdin LineBuffering
ghci> interact id
hello world
hello world
pressing control-D after the next RETURN
pressing control-D after the next RETURN
<stdin>: hGetBuffering: illegal operation (handle is closed)
或者
interact
不打算以这种方式使用,我应该撰写自定义的IO
函数吗?
是的,它不打算以这种方式使用。 interact
旨在使用所有输入并指示所有输出。如果你想使用line-wise输入,你可以编写自己的行式交互方法(或使用外部库):
import Control.Monad (when)
interactLine :: (String -> String) -> IO ()
interactLine f = loop
where
loop = do
l <- getLine
when (l /= "quit") $ putStrLn (f l) >> loop