Вот альтернатива, использующая исключения.
Сначала мы объявляем пользовательский тип исключения, содержащий наш ExitCode
import Control.Exception
import System.Exit
data TerminationException = TE ExitCode
deriving Show
instance Exception TerminationException where
Затем мы можем использовать его в чистом коде, бросаяисключение по мере необходимости.
example :: String -> Int
example s = let
j = read s
in case j of
0 -> j
_ -> throw (TE (ExitFailure 84))
Обратите внимание, что вышеприведенный read
приведет к аварийному завершению программы, если входная строка не проанализирует число. Я включил это только для того, чтобы быть как можно ближе к исходному коду, но вместо этого было бы лучше использовать readMaybe
или reads
.
Затем мы можем определить небольшой обработчик исключений.
withExit :: IO a -> IO a
withExit action = action `catch` (\(TE code) -> exitWith code)
Наконец, нам нужно обернуть main
с помощью нашего обработчика следующим образом.
main :: IO ()
main = withExit $ do
putStrLn "hello 1"
print (example "0") -- passes
putStrLn "hello 2"
print (example "1") -- ** --
putStrLn "hello 3"
Вышеуказанное main
вызывает исключение в строке, отмеченной **
,Там ничего не print
ed и программа закрывается с кодом возврата 84
, как указано в example
.