content: {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  {-# LANGUAGE TypeOperators #-}
  -- |
  -- Module:       Control.Monad.Freer.Exception
  -- Description:  An Exception effect and handler.
  -- Copyright:    (c) 2016 Allele Dev; 2017 Ixperta Solutions s.r.o.
  -- License:      BSD3
  -- Maintainer:   ixcom-core@ixperta.com
  -- Stability:    experimental
  -- Portability:  GHC specific language extensions.
  --
  -- Composable handler for Exception effects. Communicates success\/failure
  -- via an 'Either' type.
  --
  -- Using <http://okmij.org/ftp/Haskell/extensible/Eff1.hs> as a starting point.
  module Control.Monad.Freer.Exception
      ( Exc(..)
      , throwError
      , runError
      , catchError
      )
    where
  
  import Control.Applicative (pure)
  import Data.Either (Either(Left, Right))
  import Data.Function ((.))
  
  import Control.Monad.Freer.Internal (Eff, Member, handleRelay, interpose, send)
  
  
  --------------------------------------------------------------------------------
                             -- Exceptions --
  --------------------------------------------------------------------------------
  
  -- | Exceptions of the type @e :: *@ with no resumption.
  newtype Exc e a = Exc e
  
  -- | Throws an error carrying information of type @e :: *@.
  throwError :: Member (Exc e) effs => e -> Eff effs a
  throwError e = send (Exc e)
  
  -- | Handler for exception effects. If there are no exceptions thrown, returns
  -- 'Right'. If exceptions are thrown and not handled, returns 'Left', while
  -- interrupting the execution of any other effect handlers.
  runError :: Eff (Exc e ': effs) a -> Eff effs (Either e a)
  runError = handleRelay (pure . Right) (\(Exc e) _k -> pure (Left e))
  
  -- | A catcher for Exceptions. Handlers are allowed to rethrow exceptions.
  catchError
      :: Member (Exc e) effs
      => Eff effs a
      -> (e -> Eff effs a)
      -> Eff effs a
  catchError m handle = interpose pure (\(Exc e) _k -> handle e) m
  