Haskell - 我如何突破互动?

时间:2016-05-13 09:05:21

标签: loops haskell input io user-input

我正在使用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函数吗?

1 个答案:

答案 0 :(得分:6)

  

我该如何突破interact

你做不到。您可以将interact f视为getContents >>= putStrLn . fgetContents将关闭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