Обработка Control-C не работает с catch
: может быть связана с GHC # 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
и может быть связана с GHC # 2301: правильная обработка SIGINT / SIGQUIT .
В следующей версии вместо этого используется PosixAPI для установки обработчика постоянных сигналов для 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-C, нажимаемые несколько раз:
>>> ^C
keyboardSignal
>>> ^C
keyboardSignal
>>> ^C
keyboardSignal
Если не используется API Posix, установитеОбработчик постоянных сигналов в Windows требует повторного вызова исключения каждый раз, когда оно перехватывается, как описано в http://suacommunity.com/dictionary/signals.php