{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} #if MTL {-# OPTIONS_GHC -fno-warn-orphans #-} #endif module Control.Effect.Exception ( EffectException, Exception, runException, raise, except ) where import Control.Effect.Bracket import Control.Monad.Effect #ifdef MTL import Data.Type.Row import qualified Control.Monad.Error.Class as E instance (EffectBracket s l, Member (Exception s e) l, Exception s e ~ InstanceOf Exception l) => E.MonadError e (Effect l) where throwError = raise catchError = except #endif -- | An effect that describes the possibility of failure. newtype Exception s e a = Exception (Tag s e -> a) type instance Is Exception f = IsException f type family IsException f where IsException (Exception s e) = 'True IsException f = 'False class (EffectBracket s l, MemberEffect Exception (Exception s e) l) => EffectException s e l instance (EffectBracket s l, MemberEffect Exception (Exception s e) l) => EffectException s e l -- | Raises an exception. raise :: EffectException s e l => e -> Effect l a raise e = sendEffect (Exception (\tag -> raiseWith tag e)) -- | Handles an exception. Intended to be used in infix form. -- -- > myComputation `except` \ex -> doSomethingWith ex except :: EffectException s e l => Effect l a -> (e -> Effect l a) -> Effect l a except x f = sendEffect (Exception (\tag -> exceptWith tag x f)) -- | Completely handles an exception effect. runException :: (EffectBracket s l, Show e) => Effect (Exception s e ':+ l) a -> Effect l (Either e a) runException effect = do tag <- newTag show exceptWith tag (eliminate (return . Right) (\(Exception f) k -> k (f tag)) effect) (return . Left)