Haskell - 我如何打破互动?
Haskell - How do I break out of interact?
我正在使用 interact
逐步处理一些用户输入(具体来说,这是一个国际象棋程序)。但是,我还没有找到一种方法来处理用户可能只想跳出循环并从头开始这场国际象棋比赛的情况。
当我在 ghci 中执行正常程序时,按 Ctrl-C
不会退出整个 ghci,只会停止程序本身并允许我继续执行其他一些程序。但是,如果我在控制台中按 Ctrl-C
并使 interact
功能生效,则会显示以下消息:
^CInterrupted.
*Main>
<stdin>: hGetChar: illegal operation (handle is closed)
然后我必须重新启动 ghci。
我也想过捕捉特殊的用户输入,例如 "exit",但是,由于 interact
的类型是 interact :: (String -> String) -> IO ()
,输入必须通过函数类型 (String -> String)
首先,我还没有找到让该函数通知主 IO 它应该退出的方法。
我该如何突破interact
?还是 interact
不打算以这种方式使用,我应该编写自定义 IO 函数?
How should I break out of interact
?
你不能。您可以将 interact f
视为 getContents >>= putStrLn . f
。 getContents
将关闭 stdin
上的句柄。任何进一步的读取操作都会失败。
The literal character ^D gets shown in the terminal
这是 readline 的问题。 GHCi 将 stdin
的缓冲方法从 LineBuffer
更改为 NoBuffering
以优化使用 readline。如果要用^D
退出interact
,需要改变缓冲方式:
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)
Or is interact
not intended to be used this way and I should compose custom IO
functions?
是的,它不适合以这种方式使用。 interact
意味着使用所有输入并指示所有输出。如果你想使用line-wise input,你可以自己写line-wise interact方法(或者使用外部库):
import Control.Monad (when)
interactLine :: (String -> String) -> IO ()
interactLine f = loop
where
loop = do
l <- getLine
when (l /= "quit") $ putStrLn (f l) >> loop
我正在使用 interact
逐步处理一些用户输入(具体来说,这是一个国际象棋程序)。但是,我还没有找到一种方法来处理用户可能只想跳出循环并从头开始这场国际象棋比赛的情况。
当我在 ghci 中执行正常程序时,按 Ctrl-C
不会退出整个 ghci,只会停止程序本身并允许我继续执行其他一些程序。但是,如果我在控制台中按 Ctrl-C
并使 interact
功能生效,则会显示以下消息:
^CInterrupted.
*Main>
<stdin>: hGetChar: illegal operation (handle is closed)
然后我必须重新启动 ghci。
我也想过捕捉特殊的用户输入,例如 "exit",但是,由于 interact
的类型是 interact :: (String -> String) -> IO ()
,输入必须通过函数类型 (String -> String)
首先,我还没有找到让该函数通知主 IO 它应该退出的方法。
我该如何突破interact
?还是 interact
不打算以这种方式使用,我应该编写自定义 IO 函数?
How should I break out of
interact
?
你不能。您可以将 interact f
视为 getContents >>= putStrLn . f
。 getContents
将关闭 stdin
上的句柄。任何进一步的读取操作都会失败。
The literal character ^D gets shown in the terminal
这是 readline 的问题。 GHCi 将 stdin
的缓冲方法从 LineBuffer
更改为 NoBuffering
以优化使用 readline。如果要用^D
退出interact
,需要改变缓冲方式:
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)
Or is
interact
not intended to be used this way and I should compose customIO
functions?
是的,它不适合以这种方式使用。 interact
意味着使用所有输入并指示所有输出。如果你想使用line-wise input,你可以自己写line-wise interact方法(或者使用外部库):
import Control.Monad (when)
interactLine :: (String -> String) -> IO ()
interactLine f = loop
where
loop = do
l <- getLine
when (l /= "quit") $ putStrLn (f l) >> loop