Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Cooked.Ltl
Description
This modules provides the infrastructure to modify sequences of transactions using LTL formulaes with atomic modifications. This idea is to describe when to apply certain modifications within a trace. This is to be replaced later on with a dependency to https://github.com/tweag/graft.
Synopsis
- data Ltl a
- nowLater :: Monoid a => Ltl a -> [(a, Ltl a)]
- nowLaterList :: Monoid a => [Ltl a] -> [(a, [Ltl a])]
- data LtlOp (modification :: Type) (builtin :: Type -> Type) :: Type -> Type where
- data Staged (op :: Type -> Type) :: Type -> Type where
- interpLtl :: InterpLtl modification builtin m => Staged (LtlOp modification builtin) a -> StateT [Ltl modification] m a
- interpLtlAndPruneUnfinished :: InterpLtl modification builtin m => Staged (LtlOp modification builtin) a -> StateT [Ltl modification] m a
- class MonadPlus m => InterpLtl modification builtin m where
- interpBuiltin :: builtin a -> StateT [Ltl modification] m a
- class Monad m => MonadModal m where
- type Modification m :: Type
- modifyLtl :: Ltl (Modification m) -> m a -> m a
Documentation
Type of LTL formulas with atomic formulas of type a
. Think of a
as a
type of "modifications", then a value of type Ltl a
describes where to
apply modifications. Since it does not make (obvious) sense to talk of a
negated modification or of one modification (possibly in the future) to imply
another modification, implication and negation are absent.
Constructors
LtlTruth | The "do nothing" modification that never fails |
LtlFalsity | The modification that never applies (i.e. always fails) |
LtlAtom a | The modification that applies a given atomic modification at the | current time step |
LtlOr (Ltl a) (Ltl a) | Disjunction will be interpreted in an "intuitionistic" way, i.e. as branching into the "timeline" where the left disjunct holds and the one where the right disjunct holds. In that sense, it is an exclusive or, as it does not introduce the branch where both disjuncts hold. |
LtlAnd (Ltl a) (Ltl a) | Conjunction will be interpreted as "apply both modifications". Attention: The "apply both" operation will be user-defined for atomic modifications, so that conjunction may for example fail to be commutative if the operation on atomic modification is not commutative. |
LtlNext (Ltl a) | Assert that the given formula holds at the next time step. |
LtlUntil (Ltl a) (Ltl a) | Assert that the first formula holds at least until the second one begins to hold, which must happen eventually. The formulas a `LtlUntil` b and
> b are equivalent. |
LtlRelease (Ltl a) (Ltl a) | Assert that the second formula has to be true up to and including the
point when the first one becomes true; if that never happens, the second
formula has to remain true forever. View this as dual to a `LtlRelease` b and
> b are equivalent. |
nowLater :: Monoid a => Ltl a -> [(a, Ltl a)] Source #
Split an LTL formula that describes a modification of a computation into a
list of (doNow, doLater)
pairs, where
doNow
is the modification to be applied to the current time step,doLater
is an LTL formula describing the modification that should be applied from the next time step onwards, and
The return value is a list because a formula might be satisfied in different
ways. For example, the modification described by a
might be
accomplished by applying the modification LtlUntil
bb
right now, or by applying a
right now and a
from the next step onwards; the returned list
will contain these two options.LtlUntil
b
Modifications should form a Monoid
, where mempty
is the do-nothing
modification, and <>
is the composition of modifications. We interpret a
<> b
as the modification that first applies b
and then a
. Attention:
Since we use <>
to define conjunction, if <>
is not commutative,
conjunction will also fail to be commutative!
nowLaterList :: Monoid a => [Ltl a] -> [(a, [Ltl a])] Source #
Say we're passing around more than one formula from each time step to the
next, where the intended meaning of a list of formulas is the modification
that applies the first formula in the list first, then the second formula,
then the third and so on. We'd still like to compute a list of (doNow,
doLater)
pairs as in nowLater
, only that the doLater
should again be a
list of formulas.
data LtlOp (modification :: Type) (builtin :: Type -> Type) :: Type -> Type where Source #
The idea is that a value of type Staged (LtlOp modification builtin) a
describes a set of (monadic) computations that return an a
such that
- every step of the computations that returns a
b
is reified as abuiltin b
, and - every step can be modified by a
modification
.
Operations for computations that can be modified using LTL formulas.
Constructors
StartLtl :: Ltl modification -> LtlOp modification builtin () | The operation that introduces a new LTL formula that should be used to modify the following computations. Think of this operation as coming between time steps and adding a new formula to be applied before all of the formulas that should already be applied to the next time step. |
StopLtl :: LtlOp modification builtin () | The operation that removes the last LTL formula that was introduced. If
the formula is not yet |
Builtin :: builtin a -> LtlOp modification builtin a |
Instances
data Staged (op :: Type -> Type) :: Type -> Type where Source #
The freer monad on op
. We think of this as the AST of a computation with
operations of types op a
.
Instances
interpLtl :: InterpLtl modification builtin m => Staged (LtlOp modification builtin) a -> StateT [Ltl modification] m a Source #
Interpret a Staged
computation into a suitable domain, using the function
interpBuiltin
to interpret the builtins.
interpLtlAndPruneUnfinished :: InterpLtl modification builtin m => Staged (LtlOp modification builtin) a -> StateT [Ltl modification] m a Source #
Interpret a Staged
computation into a suitable domain, using the function
interpBuiltin
to interpret the builtins. At the end of the computation,
prune branches that still have unfinished
modifications applied to them.
See the discussion on the regression test case for PRs 110 and 131 in
hs
for a discussion on why this function has to exist.
class MonadPlus m => InterpLtl modification builtin m where Source #
To be a suitable semantic domain for computations modified by LTL formulas,
a monad m
has to
- have the right
builtin
functions, which can be modified by the rightmodification
s, - be a
MonadPlus
, because one LTL formula might yield different modified versions of the computation, and
This type class only requires from the user to specify how to interpret the
(modified) builtins. In order to do so, it passes around the formulas that
are to be applied to the next time step in a StateT
. A common idiom to
modify an operation should be this:
interpBuiltin op = get >>= msum . map (\(now, later) -> applyModification now op <* put later) . nowLaterList
(But to write this, modification
has to be a Monoid
to make
nowLaterList
work!) Look at the tests for this module and at
Cooked.MockChain.Monad.Staged for examples of how to use this type class.
Methods
interpBuiltin :: builtin a -> StateT [Ltl modification] m a Source #
class Monad m => MonadModal m where Source #
Monads that allow modifications with LTL formulas.
Associated Types
type Modification m :: Type Source #
Methods
modifyLtl :: Ltl (Modification m) -> m a -> m a Source #
Instances
MonadModal (Staged (LtlOp modification builtin)) Source # | |