spectacle-1.0.0: src/Language/Spectacle/Syntax/Error.hs
-- | The 'Error' effect for throwing exceptions which can be caught.
--
-- @since 1.0.0
module Language.Spectacle.Syntax.Error
( Error (ThrowE),
Effect (CatchE),
throwE,
catchE,
runError,
)
where
import Data.Functor.Loom (hoist, runLoom, (~>~))
import Language.Spectacle.Lang
( Effect,
Lang (Op, Pure, Scoped),
Member,
decomposeOp,
decomposeS,
scope,
send,
)
import Language.Spectacle.Syntax.Error.Internal (Effect (CatchE), Error (ThrowE))
-- -------------------------------------------------------------------------------------------------
-- | Throw an error of type @e@, escaping the current continuation up to the nearest enclosing
-- 'catchE'.
--
-- @since 1.0.0
throwE :: Member (Error e) effs => e -> Lang ctx effs a
throwE e = send (ThrowE e)
-- | Catch an error of type @e@ continuting from the provided function if an error was thrown.
--
-- @since 1.0.0
catchE :: Member (Error e) effs => Lang ctx effs a -> (e -> Lang ctx effs a) -> Lang ctx effs a
catchE m f = scope (CatchE m f)
-- | Discharge an 'Error' effect into either an error or the result of a successful computation.
--
-- @since 1.0.0
runError :: Lang ctx (Error e ': effs) a -> Lang ctx effs (Either e a)
runError = \case
Pure x -> pure (Right x)
Op op k -> case decomposeOp op of
Left other -> Op other (runError . k)
Right (ThrowE exc) -> pure (Left exc)
Scoped scoped loom -> case decomposeS scoped of
Left other -> Scoped other loom'
Right (CatchE m catch) -> do
x <- runLoom loom' m
either (runLoom loom' . catch) (pure . pure) x
where
loom' = loom ~>~ hoist runError