Я реализую REPL для интерпретатора схемы в Haskell, и я хотел бы обрабатывать некоторые асинхронные события, такие как UserInterrupt, StackOverflow, HeapOverflow и т. д. В принципе, я бы хотел остановить текущее вычисление при возникновении UserInterrupt и распечатать подходящее сообщение при возникновении StackOverflow и HeapOverflow и т. д. Я реализовал это следующим образом:
repl evaluator = forever $ (do
putStr ">>> " >> hFlush stdout
out <- getLine >>= evaluator
if null out
then return ()
else putStrLn out)
`catch`
onUserInterrupt
onUserInterrupt UserInterrupt = putStrLn "\nUserInterruption"
onUserInterrupt e = throw e
main = do
interpreter <- getMyLispInterpreter
handle onAbort (repl $ interpreter "stdin")
putStrLn "Exiting..."
onAbort e = do
let x = show (e :: SomeException)
putStrLn $ "\nAborted: " ++ x
Он работает, как ожидалось, с одним исключением. Если я запускаю интерпретатор и нажимаю Ctrl-Z + Enter, я получаю:
>>> ^Z
Aborted: <stdin>: hGetLine: end of file
Exiting...
Верно. Но если я запускаю интерпретатор и нажимаю Ctrl-C, а затем Ctrl-Z + Enter, я получаю:
>>>
UserInterruption
>>> ^Z
И он зависает, и я больше не могу использовать интерпретатор. Однако, если я снова нажму Ctrl-C, REPL разблокируется. Я много искал и не могу понять причину этого. Кто-нибудь может мне объяснить?
Большое спасибо!