| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Effect.Internal
Synopsis
- data Freer f a where
- newtype Fixpoint (f :: (Type -> Type) -> Type -> Type) (g :: (Type -> Type) -> Type -> Type) :: Type -> Type where
- class InterpretOneLayer f g m where
- interpretOneLayer :: (forall b. Fixpoint g f b -> m b) -> f (Fixpoint g f) a -> m a
- class InterpretOneLayerState x f g m where
- interpretOneLayerState :: (forall b. x -> Fixpoint g f b -> m (b, x)) -> x -> f (Fixpoint g f) a -> m (a, x)
- type Effect = (Type -> Type) -> Type -> Type
- data JoinedEffects (ops :: [Effect]) :: Effect where
- JoinedEffectsHere :: op m a -> JoinedEffects (op ': ops) m a
- JoinedEffectsThere :: JoinedEffects ops m a -> JoinedEffects (op ': ops) m a
- class EffectInject (op :: Effect) (ops :: [Effect]) | ops -> op where
- effectInject :: op m a -> JoinedEffects ops m a
- type AST ops = Fixpoint Freer (JoinedEffects ops)
- astInject :: EffectInject op ops => op (AST ops) a -> AST ops a
- class InterpretEffect m op where
- interpretEffect :: (forall b. AST ops b -> m b) -> op (AST ops) a -> m a
- data ConstraintList :: (a -> Constraint) -> [a] -> Type where
- ConstraintNil :: ConstraintList c '[]
- ConstraintCons :: c ty => ConstraintList c tys -> ConstraintList c (ty ': tys)
- class InterpretEffects m ops where
- interpretEffects :: ConstraintList (InterpretEffect m) ops
- interpretAST :: (Monad m, InterpretEffects m ops) => AST ops a -> m a
- class InterpretEffectStateful (t :: Type -> Type) m op where
- interpretEffectStateful :: (forall b y. t y -> AST ops b -> m (b, t y)) -> t x -> op (AST ops) a -> m (a, t x)
- class InterpretEffectsStateful t m ops where
- interpretASTStateful :: (Monad m, InterpretEffectsStateful t m ops) => t x -> AST ops a -> m (a, t x)
The freer monad
Instances
Fixpoint functors
This is a generalisation/analogy with constructions like
data Fix = f (Fix f)
Here, f is of kind Type -> Type. The first insight is that this works
for arbitrary kinds k, i.e. for any f :: k -> k. The second step is
noting that for k = Type -> Type, we can also build something that
alternates between to fs. This is that type:
newtype Fixpoint (f :: (Type -> Type) -> Type -> Type) (g :: (Type -> Type) -> Type -> Type) :: Type -> Type where Source #
Constructors
| Fixpoint | |
Fields
| |
Instances
Interpreting fixpoint functors layer by layer
class InterpretOneLayer f g m where Source #
The idea of this class: If you have InterpretOneLayer f g m and
InterpretOneLayer g f m, it's pretty easy to obtain a function
interpretFixpoint :: (InterpretOneLayer f g m, InterpretOneLayer g f m) => Fixpoint f g a -> m a fromFixpoint = interpretOneLayer fromFixpoint . unFixpoint
which calls the two interpretOneLayer functions mutually recursively.
Methods
interpretOneLayer :: (forall b. Fixpoint g f b -> m b) -> f (Fixpoint g f) a -> m a Source #
Instances
| Monad m => InterpretOneLayer Freer h m Source # | |
Defined in Effect.Internal | |
Interpreting fixpoint functors layer by layer, statefully
We could be even more generic and re-use the machinery from the last
section, if we're willing to stack another StateT monad transformer. I
chose this presentation because it makes interpretOneLayerState easier to
understand and use later on.
class InterpretOneLayerState x f g m where Source #
Methods
interpretOneLayerState :: (forall b. x -> Fixpoint g f b -> m (b, x)) -> x -> f (Fixpoint g f) a -> m (a, x) Source #
Instances
| Monad m => InterpretOneLayerState x Freer h m Source # | |
Defined in Effect.Internal | |
Effect types
data JoinedEffects (ops :: [Effect]) :: Effect where Source #
Constructors
| JoinedEffectsHere :: op m a -> JoinedEffects (op ': ops) m a | |
| JoinedEffectsThere :: JoinedEffects ops m a -> JoinedEffects (op ': ops) m a |
Instances
class EffectInject (op :: Effect) (ops :: [Effect]) | ops -> op where Source #
Is a given type of effects an element of a list of effect types?
In writing "reification" instances, a useful idiom is something like
instance EffectInject (MonadWriterEffect w) ops => MonadWriter (AST ops)
which will define "writer-like syntax" for all lists of effects that
contain 'WriterEffect w'. This idiom is also the reason for the functional
dependency in the class: ops must contain enough information to determine
op.
Users of the library should't write instances of this type, as they're
generated automatically. Also, "reification" instances like the one above
aren't written by hand, usually. Macros like makeEffect do this.
Methods
effectInject :: op m a -> JoinedEffects ops m a Source #
Instances
| EffectInject op (op ': ops) Source # | |
Defined in Effect.Internal Methods effectInject :: forall (m :: Type -> Type) a. op m a -> JoinedEffects (op ': ops) m a Source # | |
| EffectInject x ops => EffectInject x (y ': ops) Source # | |
Defined in Effect.Internal Methods effectInject :: forall (m :: Type -> Type) a. x m a -> JoinedEffects (y ': ops) m a Source # | |
Abstract syntax trees for a list of effect types
type AST ops = Fixpoint Freer (JoinedEffects ops) Source #
An abstract syntax tree which may use Effects of types ops
astInject :: EffectInject op ops => op (AST ops) a -> AST ops a Source #
Low-level convenience function to build the "singleton" AST
corresponding to one effect.
Interpreting ASTs
class InterpretEffect m op where Source #
Write an instance of this class to define the "standard" interpretation of an effect type into a suitable domain.
If you want to use the function interpretAST, this class has to be
implemented for all effect types you're using in your AST. In the normal
case, you won't do this by hand, but generate the instance (and others)
using a macro like makeEffect.
Compared to logics like Logic.Ltl, this is a low-level class; in the standard applications of these logics, you'll never have to directly interact with this class.
Methods
interpretEffect :: (forall b. AST ops b -> m b) -> op (AST ops) a -> m a Source #
Given a function that describes how to interpret ASTs and an effect,
return the interpretation of the effect.
Instances
data ConstraintList :: (a -> Constraint) -> [a] -> Type where Source #
A list of constraints, reified as a datatype. Matching on the constructors will bring the constraints in scope.
This trick is used in the functions interpretAST and
interpretASTStateful: while deconstructing the JoinedEffects to obtain
the individual effects to be interpreted through their InterpretEffect (or
InterpretEffectStateful) instances, the instances are brought into scope
by deconstructing a matching ConstraintList.
Constructors
| ConstraintNil :: ConstraintList c '[] | |
| ConstraintCons :: c ty => ConstraintList c tys -> ConstraintList c (ty ': tys) |
class InterpretEffects m ops where Source #
The constraint that all effects ops are interpretable (in the sense of
InterpretEffect) into m.
You should never have to manually write an instance of this class, it should always be inferred.
Methods
interpretEffects :: ConstraintList (InterpretEffect m) ops Source #
Instances
| InterpretEffects m ('[] :: [(Type -> Type) -> Type -> Type]) Source # | |
Defined in Effect.Internal Methods interpretEffects :: ConstraintList (InterpretEffect m) '[] Source # | |
| (InterpretEffect m op, InterpretEffects m ops) => InterpretEffects m (op ': ops) Source # | |
Defined in Effect.Internal Methods interpretEffects :: ConstraintList (InterpretEffect m) (op ': ops) Source # | |
interpretAST :: (Monad m, InterpretEffects m ops) => AST ops a -> m a Source #
If all effect types in ops have an InterpretEffect m instance, this
function will interpret the AST into m.
Interpreting ASTs, statefully
class InterpretEffectStateful (t :: Type -> Type) m op where Source #
Write an instance of this class to define the "statefully modified"
interpretation of an effect type into a suitable domain. The intuition is
that you interpret effects of type ops into the domain m, while also
passing a state of type t x from step to step. This state will control how
effects are actually implemented in m.
If you want to use the function interpretASTStateful, this class has to be
implemented for all effect types in the AST you're using.
Compared to logics like Logic.Ltl, this is a low-level class; in the standard applications of these logics, you'll never have to directly interact with this class.
Methods
interpretEffectStateful :: (forall b y. t y -> AST ops b -> m (b, t y)) -> t x -> op (AST ops) a -> m (a, t x) Source #
Given a function that describes how to interpret ASTs statefully, a
current "interpretation state", and an effect, return the stateful
interpretation of the effect.
Instances
| MonadFail m => InterpretEffectStateful x m MonadFailEffect Source # | A "passthough" instance for |
Defined in Effect.Fail.Passthrough Methods interpretEffectStateful :: forall (ops :: [Effect]) x0 a. (forall b y. x y -> AST ops b -> m (b, x y)) -> x x0 -> MonadFailEffect (AST ops) a -> m (a, x x0) Source # | |
| MonadIO m => InterpretEffectStateful x m MonadIOEffect Source # | A "passthough" instance for |
Defined in Effect.IO.Passthrough Methods interpretEffectStateful :: forall (ops :: [Effect]) x0 a. (forall b y. x y -> AST ops b -> m (b, x y)) -> x x0 -> MonadIOEffect (AST ops) a -> m (a, x x0) Source # | |
| MonadError e m => InterpretEffectStateful x m (MonadErrorEffect e) Source # | A "passthough" instance for |
Defined in Effect.Error.Passthrough Methods interpretEffectStateful :: forall (ops :: [Effect]) x0 a. (forall b y. x y -> AST ops b -> m (b, x y)) -> x x0 -> MonadErrorEffect e (AST ops) a -> m (a, x x0) Source # | |
| MonadWriter e m => InterpretEffectStateful x m (MonadWriterEffect e) Source # | A "passthough" instance for |
Defined in Effect.Writer.Passthrough Methods interpretEffectStateful :: forall (ops :: [Effect]) x0 a. (forall b y. x y -> AST ops b -> m (b, x y)) -> x x0 -> MonadWriterEffect e (AST ops) a -> m (a, x x0) Source # | |
| (MonadPlus m, InterpretEffect m op, InterpretNextBind t m op) => InterpretEffectStateful (NextBind t) m op Source # | |
class InterpretEffectsStateful t m ops where Source #
The constraint that all effects ops are statefully interpretable with a
state of type t into m (in the sense of InterpretEffectStateful).
You should never have to manually write an instance of this class, it should always be inferred.
Methods
interpretEffectsStateful :: ConstraintList (InterpretEffectStateful t m) ops Source #
Instances
| InterpretEffectsStateful t m ('[] :: [(Type -> Type) -> Type -> Type]) Source # | |
Defined in Effect.Internal Methods interpretEffectsStateful :: ConstraintList (InterpretEffectStateful t m) '[] Source # | |
| (InterpretEffectStateful t m op, InterpretEffectsStateful t m ops) => InterpretEffectsStateful t m (op ': ops) Source # | |
Defined in Effect.Internal Methods interpretEffectsStateful :: ConstraintList (InterpretEffectStateful t m) (op ': ops) Source # | |
interpretASTStateful :: (Monad m, InterpretEffectsStateful t m ops) => t x -> AST ops a -> m (a, t x) Source #
If all effect types in ops have an InterpretEffectStateful t m
instance, this function will interpret the AST, starting at a given
initial "interpretation state" of type t x for some x.