{-# LANGUAGE TemplateHaskell #-}
-- | This is referenced from README.md
module Main where
import Control.Exception.Safe (throwM, MonadCatch, catch, SomeException)
import Control.Exception.Throwable (GeneralException(..), generalException, IndexOutOfBoundsException(..))
import Control.Exception.Throwable.TH (declareException)
{- !! These line is needed by declareException !! -}
import Control.Exception.Safe (Exception)
import Data.Typeable (Typeable)
{- ---------------------------------------------- -}
-- This is same as
--
-- data MyException a = MyException
-- { myExceptionCause :: String
-- , myExceptionClue :: a
-- } deriving (Typeable)
--
-- instance Show a => Show (MyException a) where
-- ...
-- instance (Typeable a, Show a) => Exception (MyException a)
--
declareException "MyException" ["MyException"]
-- ^ the second argument (the list of String) will be made as a value constructor.
-- This is same as
--
-- data TwoException a =
-- FirstException
-- { firstExceptionCause :: String
-- , firstExceptionClue :: a
-- } |
-- SecondException
-- { secondExceptionCause :: String
-- , secondExceptionClue :: a
-- } deriving (Typeable)
--
-- instance Show a => (TwoException a) where
-- ...
-- instance (Typeable a, Show a) => Exception (TwoException a)
--
declareException "TwoException" ["FirstException", "SecondException"]
main :: IO ()
main = do
print $ ([1..4] `at` 5 :: Either SomeException Int)
print $ MyException "hi" 10
print $ myException "poi"
-- ^ a (fake) value constructor,
-- this is same as `MyException` but without a clue value.
print (foo :: Either SomeException Int)
print $ FirstException "chino" 20
print $ firstException "cocoa"
print $ secondException "rize"
--
-- vvv output result vvv
--
-- Left IndexOutOfBoundsException: "index is too big"
-- MyException: "hi"
-- MyException: "poi"
-- Left FooException: poi poi poi !?
-- IndexOutOfBoundsException,
-- IOException',
-- IllegalArgumentException,
-- and GeneralException is presented by default.
at :: (MonadCatch m, Typeable a, Show a) => [a] -> Int -> m a
at xs index = do
if index < length xs
then return $ xs !! index
else throwM $ IndexOutOfBoundsException "index is too big" (xs, index)
--else throwM $ indexOutOfBoundsException' "index is too big"
-- You can use above code without some clue
-- If you don't want to use TemplateHaskell (Control.Exception.Throwable.TH),
-- you can use GeneralException and generalException instead !
--
-- data GeneralException a = GeneralException
-- { exceptionName :: String -- ^ This should be named by 'PascalCase' for show, for example: "MyOperation", "Database"
-- , exceptionCause :: String -- ^ The message for the cause of the exception
-- , exceptionClue :: a -- ^ The clue of the exception. This can be anything of Show instance
-- }
--
-- generalException :: String -> String -> GeneralException ()
-- generalException name cause = GeneralException name cause ()
--
foo :: (MonadCatch m, Typeable a, Show a) => m a
foo = throwM $ generalException "FooException" "poi poi poi !?"
-- This is same as `GeneralException "FooException" "poi poi poi !?" ()`