Ответ 1
Обработка Control-C не работает с catch
: может быть связана с GHС# 2301: правильная обработка SIGINT/SIGQUIT
Вот рабочий тестовый файл с удаленным evaluator
:
module Main where
import Prelude hiding (catch)
import Control.Exception ( SomeException(..),
AsyncException(..)
, catch, handle, throw)
import Control.Monad (forever)
import System.IO
repl :: IO ()
repl = forever $ (do
putStr ">>> " >> hFlush stdout
out <- getLine
if null out
then return ()
else putStrLn out)
`catch`
onUserInterrupt
onUserInterrupt UserInterrupt = putStrLn "\nUserInterruption"
onUserInterrupt e = throw e
main = do
handle onAbort repl
putStrLn "Exiting..."
onAbort e = do
let x = show (e :: SomeException)
putStrLn $ "\nAborted: " ++ x
В Linux, Control-Z не пойман, как упоминал Sjoerd. Возможно, вы находитесь в Windows, где Control-Z используется для EOF. Мы можем сигнализировать EOF на Linux с помощью Control-D, который воспроизводит поведение, которое вы видели:
>>> ^D
Aborted: <stdin>: hGetLine: end of file
Exiting...
EOF обрабатывается вашей функцией handle/onAbort
, а Control-C обрабатывается catch/onUserInterrupt
. Проблема здесь в том, что ваша функция repl
будет захватывать только первый Control-C - тестовый тест можно упростить, удалив функцию handle/onAbort
. Как отмечалось выше, обработка Control-C не работает с catch
может быть связана с GHС# 2301: правильная обработка SIGINT/SIGQUIT.
В следующей версии вместо этого используется Posix API для установки стойкого обработчика сигналов для Control-C:
module Main where
import Prelude hiding (catch)
import Control.Exception ( SomeException(..),
AsyncException(..)
, catch, handle, throw)
import Control.Monad (forever)
import System.IO
import System.Posix.Signals
repl :: IO ()
repl = forever $ do
putStr ">>> " >> hFlush stdout
out <- getLine
if null out
then return ()
else putStrLn out
reportSignal :: IO ()
reportSignal = putStrLn "\nkeyboardSignal"
main = do
_ <- installHandler keyboardSignal (Catch reportSignal) Nothing
handle onAbort repl
putStrLn "Exiting..."
onAbort e = do
let x = show (e :: SomeException)
putStrLn $ "\nAborted: " ++ x
который может обрабатывать Control-Cs несколько раз:
>>> ^C
keyboardSignal
>>> ^C
keyboardSignal
>>> ^C
keyboardSignal
Если не использовать Posix API, установка стойкого обработчика сигналов в Windows требует повторного воссоздания исключения каждый раз, когда он пойман, как описано в http://suacommunity.com/dictionary/signals.php