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 f
s. 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 Effect
s 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 AST
s
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 AST
s 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 AST
s, 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 AST
s 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
.