haskell 在REPL中使用CTRL-C丢弃当前行并开始下一行

f3temu5u  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(101)

我正在用Haskell写一个REPL。其基本思想如下:

repl :: IO ()
repl = do putStr ">> "
          hFlush stdout
          input <- getLine
          ...
          repl

字符串
我想模仿一些GHCi行为,当按下CTRL-C时,REPL丢弃当前行并开始一个新的空行供用户输入。我想到SIGINT引发了AsyncExceptionUserInterrupt,这可以由catch处理。因此,在输入行上进行一些修改:

repl :: IO ()
repl = do putStr ">> "
          hFlush stdout
          input <- getLine `catch` handleCC
          repl

handleCC :: AsyncException -> IO String
handleCC _ = do putStr "\n>> "
                hFlush stdout
                getLine `catch` handleCC


handleCC中,AsyncException将再次通过递归处理,所以我肯定可以无限次中断REPL,对吗?
我当然不能第二CTRL-C仍然终止REPL。但为什么呢?

>> something^C
>> another^C
[Process exited 130]

x6yk4ghg

x6yk4ghg1#

在深入挖掘之后,我相信我可以得出结论,catch不能正确地处理异步异常,try或类似的也不能。mask似乎是一个潜在的解决方案,但我发现它的用法有点复杂,即使在文档中也是如此。
This answer通过使用POSIX API安装持久信号处理程序提供了一个工作解决方案。与我的代码集成:

import           Control.Monad        (forever)
import           System.IO            (hFlush, stdout)
import           System.Posix.Signals (Handler (Catch), installHandler, sigINT)

repl = do installHandler sigINT (Catch $ putStr "\n>> ") Nothing
          forever $ do putStr ">> "
                       hFlush stdout
                       input <- getLine
                       ...

字符串

相关问题