Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This module exports the Plan
Applicative.
>>>
:{
let example :: Plan String [Int] IO () () example = step "(a)" (step "(a.a)" (foretell [1] *> plan (threadDelay 1e6)) *> step "(a.a)" (foretell [2] *> plan (threadDelay 1e6))) *> step "(b)" (step "(b.a)" (foretell [3] *> plan (threadDelay 1e6)) *> step "(b.b)" (foretell [4] *> plan (threadDelay 1e6))) in bifoldMap id (foldMap Prelude.show) (getSteps example) :} "(a)(a.a)1(a.a)2(b)(b.a)3(b.b)4"
Some possible use cases:
- Inspect the steps of an existing
Plan
fromghci
usinggetSteps
,toForest
anddrawForest
, as a form of documentation. - If your script requires files that must be already present in the file
system, use
foretell
to annotate eachPlan
action that requires a file, then get the global list of files usinggetSteps
andfoldMap
, and check that they all exist before running thePlan
withrunPlan
. - Get progress updates for your script by declaring (possibly nested) steps
with
step
, running thePlan
withrunPlan
, and providing a notification callback withonTick
, probably usingtickToForest
anddrawForest
to render the updates. - Run a
Plan
withrunPlan
, useinstants
antoForest
on the resultingTimeline
to get the durations of each step, then usezipSteps
on the samePlan
and run it again. Now whenever a step finishes we can know if it took more or less than in the previous execution.
- data Plan s w m i o
- plan :: (Monoid w, Monad m) => m o -> Plan s w m i o
- planIO :: (Monoid w, MonadIO m) => IO o -> Plan s w m i o
- planK :: (Monoid w, Monad m) => (i -> m o) -> Plan s w m i o
- planKIO :: (Monoid w, MonadIO m) => (i -> IO o) -> Plan s w m i o
- step :: (Monoid w, Monad m) => s -> Plan s w m i o -> Plan s w m i o
- skippable :: (Monoid w, Monad m) => s -> Plan s w m i o -> Plan s w m (Maybe i) ()
- foretell :: Monad m => w -> Plan s w m i ()
- getSteps :: Plan s w m i o -> Steps s w
- data Steps s w
- mandatoriness :: Steps s w -> Steps (Mandatoriness, s) w
- data Mandatoriness
- foldSteps :: ([(w, s, Mandatoriness, r)] -> w -> r) -> Steps s w -> r
- bimapSteps :: (s -> s') -> (w -> w') -> Plan s w m i o -> Plan s' w' m i o
- zoomSteps :: Monoid w' => ((w -> Identity w) -> w' -> Identity w') -> Plan s w m i o -> Plan s w' m i o
- zipSteps :: Forest s' -> Plan s w m i o -> Maybe (Plan (s', s) w m i o)
- hoistPlan :: Monad m => (forall x. m x -> n x) -> Plan s w m i o -> Plan s w n i o
- unliftPlan :: Monad m => Plan s w m () o -> m o
- runPlan :: Monad m => m t -> Plan s w m () o -> Stream (Of (Tick s t)) m (Timeline s t, o)
- onTick :: Monad m => (tick -> m ()) -> Stream (Of tick) m r -> m r
- tickToForest :: Tick s t -> Forest (Maybe (Either t (t, Maybe t)), s)
- data Tick s t = Tick (NonEmpty (Context s t)) (Progress s t)
- data Context s t = Context {}
- data Progress s t
- data Timeline s t
- instants :: Timeline s t -> Timeline (Either t (t, t), s) t
- foldTimeline :: ([(t, s, Either (Forest s) r)] -> t -> r) -> Timeline s t -> r
- unliftPlanK :: Monad m => Plan s w m i o -> i -> m o
- runPlanK :: Monad m => m t -> Plan s w m i o -> i -> Stream (Of (Tick s t)) m (Timeline s t, o)
- class Bitraversable l => Lasagna l where
- bimap :: Bifunctor p => forall a b c d. (a -> b) -> (c -> d) -> p a c -> p b d
- bifoldMap :: Bifoldable p => forall m a b. Monoid m => (a -> m) -> (b -> m) -> p a b -> m
- bitraverse :: Bitraversable t => forall f a c b d. Applicative f => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
- extract :: Comonad w => forall a. w a -> a
- hoist :: MFunctor t => forall m n b. Monad m => (forall a. m a -> n a) -> t m b -> t n b
- effects :: Monad m => Stream (Of a) m r -> m r
Constructing plans
A computation that takes inputs of type i
and produces outputs of type
o
working in the underlying monad m
. The Applicative
instance cares
only about the outputs, the Arrow
instance cares about both inputs and
outputs.
Parts of the computation can be labeled as steps with tags of type s
.
Computations can have monoidal resource annotations of type w
.
The structure of steps and the monoidal annotations can be inspected before executing the computations.
plan :: (Monoid w, Monad m) => m o -> Plan s w m i o Source #
Lift a monadic action to a Plan
. The input type remains polymorphic.
planK :: (Monoid w, Monad m) => (i -> m o) -> Plan s w m i o Source #
Lift a Kleisli arrow to a Plan
.
Declaring steps and annotations
step :: (Monoid w, Monad m) => s -> Plan s w m i o -> Plan s w m i o Source #
Declare a step by wrapping an existing plan (which may contain substeps).
skippable :: (Monoid w, Monad m) => s -> Plan s w m i o -> Plan s w m (Maybe i) () Source #
Declare an optional step by wrapping an existing arrow plan. The step will
only be executed when the input is Just
.
This function only makes sense when using the Arrow
instance of Plan
,
because for Applicative
s an effect cannot depend on previously obtained
values.
Analyzing plans
A Forest
of steps tags of type s
interspersed with monoidal
annotations of type w
.
Bifunctor Steps Source # | |
Bitraversable Steps Source # | |
Bifoldable Steps Source # |
|
Lasagna Steps Source # |
|
Functor (Steps s) Source # | |
Foldable (Steps s) Source # | |
Traversable (Steps s) Source # | |
(Eq s, Eq w) => Eq (Steps s w) Source # | |
(Show s, Show w) => Show (Steps s w) Source # | |
Monoid w => Monoid (Steps s w) Source # | |
mandatoriness :: Steps s w -> Steps (Mandatoriness, s) w Source #
Decorate each step tag with its mandatoriness. Useful in combination with toForest
.
data Mandatoriness Source #
Steps of Plan
s constructed in Applicative
fashion are always
Mandatory
. Only steps declared with skippable
are optional.
:: ([(w, s, Mandatoriness, r)] -> w -> r) | A function that consumes a list of step tags of type |
-> Steps s w | |
-> r |
Adapting plans
Sometimes, we might need to mix Plan
s for which step tags and annotations
are of different types. These functions help with that.
bimapSteps :: (s -> s') -> (w -> w') -> Plan s w m i o -> Plan s' w' m i o Source #
Adapt the Step
value inside a Plan
without extracting it.
zoomSteps :: Monoid w' => ((w -> Identity w) -> w' -> Identity w') -> Plan s w m i o -> Plan s w' m i o Source #
Use a lens setter to "zoom" the monoidal annotations of a Plan
into a
wider monoidal context.
zipSteps :: Forest s' -> Plan s w m i o -> Maybe (Plan (s', s) w m i o) Source #
Pair each step tag s
inside a Plan
with the corresponding element of the Forest
.
If the forest doesn't have the same structure as the steps, the function
fails with Nothing
.
This function can be useful to annotate each step tag with some information,
for example the time duration of the step in a previous execution of the
plan. See Timeline
, instants
, and toForest
.
hoistPlan :: Monad m => (forall x. m x -> n x) -> Plan s w m i o -> Plan s w n i o Source #
Change the underlying monad of a Plan
.
Running plans
unliftPlan :: Monad m => Plan s w m () o -> m o Source #
Forget that there is a plan, get the underlying monadic action.
:: Monad m | |
=> m t | Monadic measurement to be taken on each tick. |
-> Plan s w m () o | Plan without input. |
-> Stream (Of (Tick s t)) m (Timeline s t, o) |
Runs a plan that doesn't need input. It returns a Stream
of Tick
updates that are emitted every time the execution advances through the
Steps
.
For each Tick
update, a monadic measurement of type t
is taken. Usually
the measurement consists in getting the current time.
When the execution finishes, a Timeline
with the measurements for each
Tick
is returned, along with the result value.
Even if the plan didn't have any steps, the Timeline
will contain a
measurement taken when the computation finished.
onTick :: Monad m => (tick -> m ()) -> Stream (Of tick) m r -> m r Source #
Specify a monadic callback for processing each Tick
update.
tickToForest :: Tick s t -> Forest (Maybe (Either t (t, Maybe t)), s) Source #
Transform a Tick
into a form more suitable for rendering with functions
like drawForest
.
A given step might not have been reached yet. It it has been reached, either it has been skipped at a certain time, or started at a certain time. If if has been started, maybe it has already finised, too.
The execution of a Plan
can make progress by skipping a step, starting a
step, or finishing a step.
A Forest
of steps tags of type s
interspersed with
measurements of type t
.
Bifunctor Timeline Source # | |
Bitraversable Timeline Source # | |
Bifoldable Timeline Source # | |
Lasagna Timeline Source # |
|
Functor (Timeline s) Source # | |
Foldable (Timeline s) Source # | |
Traversable (Timeline s) Source # | |
Comonad (Timeline s) Source # |
|
(Eq s, Eq t) => Eq (Timeline s t) Source # | |
(Show s, Show t) => Show (Timeline s t) Source # | |
instants :: Timeline s t -> Timeline (Either t (t, t), s) t Source #
Decorate each step tag with either the time the step was skipped, or the
time it was started and finished. Useful in combination with toForest
.
:: ([(t, s, Either (Forest s) r)] -> t -> r) | A function that consumes a list of step tags of type |
-> Timeline s t | |
-> r |
Running arrow plans
unliftPlanK :: Monad m => Plan s w m i o -> i -> m o Source #
Forget that there is a plan, get the underlying Kleisli arrow.
The Lasagna typeclass
class Bitraversable l => Lasagna l where Source #
Instances of Lasagna
are like Forest
s where each list of
sibling nodes of type n
is surrounded and interspersed with annotations of
type a
. Some instances might add extra information to each node, or
allow alternative branches.
Re-exports
bifoldMap :: Bifoldable p => forall m a b. Monoid m => (a -> m) -> (b -> m) -> p a b -> m #
bitraverse :: Bitraversable t => forall f a c b d. Applicative f => (a -> f c) -> (b -> f d) -> t a b -> f (t c d) #
Evaluates the relevant functions at each element in the structure, running the action, and builds a new structure with the same shape, using the elements produced from sequencing the actions.
bitraverse
f g ≡bisequenceA
.bimap
f g
For a version that ignores the results, see bitraverse_
.
Besides its usefulness with Timeline
, extract
lets you get the head of a
NonEmpty
or the second element of a tuple.
hoist :: MFunctor t => forall m n b. Monad m => (forall a. m a -> n a) -> t m b -> t n b #
Lift a monad morphism from m
to n
into a monad morphism from
(t m)
to (t n)
effects :: Monad m => Stream (Of a) m r -> m r #
Reduce a stream, performing its actions but ignoring its elements.
>>>
rest <- S.effects $ S.splitAt 2 $ each [1..5]
>>>
S.print rest
3 4 5 'effects' should be understood together with 'copy' and is subject to the rules
S.effects . S.copy = id hoist S.effects . S.copy = id
The similar effects
and copy
operations in Data.ByteString.Streaming
obey the same rules.