polysemy-resume-0.9.0.1: Polysemy error tracking
Safe HaskellNone
LanguageGHC2021

Polysemy.Resume.Interpreter.Resumable

Description

 
Synopsis

Documentation

resumable :: forall err (eff :: Effect) (r :: EffectRow). InterpreterFor eff (Stop err ': r) -> InterpreterFor (Resumable err eff) r Source #

Convert a bare interpreter for eff, which (potentially) uses Stop to signal errors, into an interpreter for Resumable. Beware: This will display unsound behaviour if: * the interpreter is wrapped with actions of another effect, as in:

  interpretEff :: InterpreterFor Eff r
  ...

  interpretEffResumable :: InterpreterFor (Resumable Text Eff) r
  interpretEffResumable sem =
  resumable (interpretEff (sem finally releaseResources))
  

In this case, releaseResources will be called after every use of Eff in sem, not after the entire thunk.

  • the interpreter of a higher-order effect uses a different interpreter after using runT/bindT. In this case, it will use the original interpreter instead.

If your use case matches one of these conditions, you'll need to use interpretResumable.

>>> run $ resumable interpretStopper (interpretResumer mainProgram)
237

raiseResumable :: forall err (eff :: Effect) (r :: EffectRow) a b. (Sem (eff ': r) a -> Sem r b) -> Sem (Resumable err eff ': r) a -> Sem r b Source #

Convenience combinator for turning an interpreter that doesn't use Stop into a Resumable.

resumableIO :: forall err (eff :: Effect) (r :: EffectRow). (Exception (StopExc err), Member (Final IO) r) => InterpreterFor eff (Stop err ': r) -> InterpreterFor (Resumable err eff) r Source #

Like resumable, but use exceptions instead of ExceptT.

interpretResumableH Source #

Arguments

:: forall err eff (r :: EffectRow). (forall x (r0 :: EffectRow). eff (Sem r0) x -> Tactical (Resumable err eff) (Sem r0) (Stop err ': r) x)

This handler function has Stop err in its stack, allowing it to absorb errors.

-> InterpreterFor (Resumable err eff) r 

Like interpretResumable, but for higher-order effects.

interpretResumable :: forall err eff (r :: [Effect]). FirstOrder eff "interpretResumable" => (forall x (r0 :: EffectRow). eff (Sem r0) x -> Sem (Stop err ': r) x) -> InterpreterFor (Resumable err eff) r Source #

Create an interpreter for Resumable err eff by supplying a handler function for eff, analogous to interpret. If the handler throws errors with Stop, they will be absorbed into Resumable, to be caught by resume in a downstream interpreter.

interpretStopperResumable ::
  InterpreterFor Stopper r
interpretStopperResumable =
  interpretResumable \case
    StopBang -> stop (Bang 13)
    StopBoom -> stop (Boom "ouch")
>>> run $ interpretStopperResumable (interpretResumer mainProgram)
237

interceptResumableUsingH :: forall err eff (r :: EffectRow) a. ElemOf (Resumable err eff) r -> (forall x (r0 :: EffectRow). eff (Sem r0) x -> Tactical (Resumable err eff) (Sem r0) (Stop err ': r) x) -> Sem r a -> Sem r a Source #

Interceptor variant of interpretResumableH.

interceptResumableUsing :: forall err eff (r :: EffectRow) a. FirstOrder eff "interceptResumableUsing" => ElemOf (Resumable err eff) r -> (forall x (r0 :: EffectRow). eff (Sem r0) x -> Sem (Stop err ': r) x) -> Sem r a -> Sem r a Source #

Interceptor variant of interpretResumable.

interceptResumableH :: forall err eff (r :: EffectRow) a. Member (Resumable err eff) r => (forall x (r0 :: EffectRow). eff (Sem r0) x -> Tactical (Resumable err eff) (Sem r0) (Stop err ': r) x) -> Sem r a -> Sem r a Source #

Interceptor variant of interpretResumableH.

interceptResumable :: forall err eff (r :: EffectRow) a. (Member (Resumable err eff) r, FirstOrder eff "interceptResumable") => (forall x (r0 :: EffectRow). eff (Sem r0) x -> Sem (Stop err ': r) x) -> Sem r a -> Sem r a Source #

Interceptor variant of interpretResumable.

resumableError :: forall err (eff :: Effect) (r :: [(Type -> Type) -> Type -> Type]). InterpreterFor eff ((Error err :: (Type -> Type) -> Type -> Type) ': (Stop err ': r)) -> InterpreterFor (Resumable err eff) r Source #

Convert an interpreter for eff that uses Error into one using Stop and wrap it using resumable.

resumableOr :: forall err (eff :: Effect) unhandled handled (r :: EffectRow). Member (Error unhandled :: (Type -> Type) -> Type -> Type) r => (err -> Either unhandled handled) -> InterpreterFor eff (Stop err ': r) -> InterpreterFor (Resumable handled eff) r Source #

Convert an interpreter for eff that throws errors of type err into a Resumable, but limiting the errors handled by consumers to the type handled, which rethrowing Errors of type unhandled.

The function canHandle determines how the errors are split.

newtype Blip =
  Blip { unBlip :: Int }
  deriving stock (Eq, Show)

bangOnly :: Boom -> Either Text Blip
bangOnly = \case
  Bang n -> Right (Blip n)
  Boom msg -> Left msg

interpretResumerPartial ::
  Member (Resumable Blip Stopper) r =>
  InterpreterFor Resumer r
interpretResumerPartial =
  interpret \ MainProgram ->
    resume (192 <$ stopBang) \ (Blip num) ->
      pure (num * 3)
>>> runError (resumableFor bangOnly interpretStopper (interpretResumerPartial mainProgram))
Right 39

resumableFor :: forall err (eff :: Effect) handled (r :: EffectRow). Member (Error err :: (Type -> Type) -> Type -> Type) r => (err -> Maybe handled) -> InterpreterFor eff (Stop err ': r) -> InterpreterFor (Resumable handled eff) r Source #

Variant of resumableOr that uses Maybe and rethrows the original error.

catchResumable :: forall err (eff :: Effect) handled (r :: EffectRow). Members '[eff, Error err :: (Type -> Type) -> Type -> Type] r => (err -> Maybe handled) -> InterpreterFor (Resumable handled eff) r Source #

Reinterpreting variant of resumableFor.

runAsResumable :: forall err (eff :: Effect) (r :: EffectRow). Members '[Resumable err eff, Stop err] r => InterpreterFor eff r Source #

Interpret an effect eff by wrapping it in Resumable and Stop and leaving the rest up to the user.