Обработка исключения UserInterrupt в Haskell

Я реализую 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 разблокируется. Я много искал и не могу понять причину этого. Кто-нибудь может мне объяснить?

Большое спасибо!

10
задан Rafael Barreto 18 August 2011 в 23:31
поделиться