{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} module Hanzo ( Mainable(..) , Termination(..) , Exit.ExitCode(..) ) where import qualified Control.Exception as Exn import qualified Control.Monad.Trans.Except as Except import qualified System.Environment as Env import qualified System.Exit as Exit import qualified System.IO as IO -- | The 'Mainable' class represents computations which can be -- encapsulated as the 'main' function of a program. class Mainable k where main :: k -> IO () guardExceptions :: IO a -> IO a guardExceptions action = do result <- Exn.try action case result of Left (e :: Exn.SomeException) -> do IO.hPutStrLn IO.stderr (Exn.displayException e) Exit.exitWith (Exit.ExitFailure 1) Right x -> pure x instance Termination r => Mainable (IO r) where main action = do r <- guardExceptions action code <- report r Exit.exitWith code instance Termination r => Mainable (Except.ExceptT String IO r) where main action = do exn <- guardExceptions (Except.runExceptT action) case exn of Left err -> do IO.hPutStrLn IO.stderr err Exit.exitWith (Exit.ExitFailure 1) Right r -> do code <- report r Exit.exitWith code instance Mainable k => Mainable ([String] -> k) where main action = do args <- Env.getArgs let rest = action args main rest -- | The 'Termination' class represents values which can be returned -- from a 'Main' function which might represent success or failure. class Termination t where report :: t -> IO Exit.ExitCode instance Termination () where report _ = pure Exit.ExitSuccess instance Termination Bool where report True = pure Exit.ExitSuccess report False = pure (Exit.ExitFailure 1) instance Termination Exit.ExitCode where report x = pure x instance Show e => Termination (Either e ()) where report (Left err) = do IO.hPutStrLn IO.stderr (show err) pure (Exit.ExitFailure 1) report (Right ()) = pure Exit.ExitSuccess instance Termination (Maybe ()) where report Nothing = pure (Exit.ExitFailure 1) report (Just ()) = pure Exit.ExitSuccess