I'm writing a REPL in Haskell. The basic idea looks like this:
repl :: IO ()
repl = do putStr ">> "
hFlush stdout
input <- getLine
...
repl
I'd like to mimic some GHCi behaviour that when CTRL-C is pressed, the REPL discards the current line and starts a new empty line for user input. It has come to my mind that SIGINT raises UserInterrupt
of AsyncException
, which can be handled by catch
. Therefore some modifications on the input line:
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
Within handleCC
, AsyncException
will be handled once more by recursion, so surely I can interrupt the REPL infinite times, right...?
Of course I can't; a second CTRL-C still terminates the REPL. But why?
>> something^C
>> another^C
[Process exited 130]