@@ -83,7 +83,7 @@ effectful program ``f`` has a type of the following form:
84.. code-block:: idris
84.. code-block:: idris
86− f : (x1 : a1) -> (x2 : a2) -> ... -> { effs } Eff t
86+ f : (x1 : a1) -> (x2 : a2) -> ... -> Eff t effs
88That is, the return type gives the effects that ``f`` supports
88That is, the return type gives the effects that ``f`` supports
89(``effs``, of type ``List EFFECT``) and the type the computation
89(``effs``, of type ``List EFFECT``) and the type the computation
@@ -92,7 +92,7 @@ following type:
93.. code-block:: idris
93.. code-block:: idris
95− treeTagAux : BTree a -> { [STATE Int] } Eff (BTree (Int, a))
95+ treeTagAux : BTree a -> Eff (BTree (Int, a)) [STATE Int]
97That is, ``treeTagAux`` has access to an integer state, because the
97That is, ``treeTagAux`` has access to an integer state, because the
98list of available effects includes ``STATE Int``. ``STATE`` is
98list of available effects includes ``STATE Int``. ``STATE`` is
@@ -141,8 +141,8 @@ following types, polymorphic in the state ``t`` they manage:
142.. code-block:: idris
142.. code-block:: idris
144− get : { [STATE t] } Eff t
144+ get : Eff t [STATE t]
145− put : t -> { [STATE t] } Eff ()
145+ put : t -> Eff () [STATE t]
147A program in ``Eff`` can call any other function in ``Eff`` provided
147A program in ``Eff`` can call any other function in ``Eff`` provided
148that the calling function supports at least the effects required by
148that the calling function supports at least the effects required by
@@ -168,7 +168,7 @@ instead of ``runPure``:
169.. code-block:: idris
169.. code-block:: idris
171− treeTagAux : BTree a -> { [STATE Int] } Eff (BTree (Int, a))
171+ treeTagAux : BTree a -> Eff (BTree (Int, a)) [STATE Int]
174 treeTag : (i : Int) -> BTree a -> IO (BTree (Int, a))
174 treeTag : (i : Int) -> BTree a -> IO (BTree (Int, a))
@@ -202,7 +202,7 @@ shown in Listing [introprog].
203 (Node Leaf "Bob" Leaf))
203 (Node Leaf "Bob" Leaf))
205− treeTagAux : BTree a -> { [STATE Int] } Eff (BTree (Int, a))
205+ treeTagAux : BTree a -> Eff (BTree (Int, a)) [STATE Int]
206 treeTagAux Leaf = pure Leaf
206 treeTagAux Leaf = pure Leaf
207 treeTagAux (Node l x r) = do l' <- treeTagAux l
207 treeTagAux (Node l x r) = do l' <- treeTagAux l
@@ -227,8 +227,8 @@ here for illustrative purposes):
228.. code-block:: idris
228.. code-block:: idris
230− runPure : {env : Env id xs} -> { xs } Eff a -> a
230+ runPure : {env : Env id xs} -> Eff a xs -> a
231− run : Applicative m => {env : Env m xs} -> { xs } Eff a -> m a
231+ run : Applicative m => {env : Env m xs} -> Eff a xs -> m a
233The ``env`` argument is implicit, and initialised automatically where
233The ``env`` argument is implicit, and initialised automatically where
234possible using default values given by instances of the following type
234possible using default values given by instances of the following type
@@ -248,8 +248,8 @@ using one of the following functions:
249.. code-block:: idris
249.. code-block:: idris
251− runPureInit : Env id xs -> { xs } Eff a -> a
251+ runPureInit : Env id xs -> Eff a xs -> a
252− runInit : Applicative m => Env m xs -> { xs } Eff a -> m a
252+ runInit : Applicative m => Env m xs -> Eff a xs -> m a
254To be well-typed, the environment must contain resources corresponding
254To be well-typed, the environment must contain resources corresponding
255exactly to the effects in ``xs``. For example, we could also have
255exactly to the effects in ``xs``. For example, we could also have
@@ -272,8 +272,7 @@ captured both of these values, e.g.:
273.. code-block:: idris
273.. code-block:: idris
275− treeTagAux : BTree a
275+ treeTagAux : BTree a -> Eff (BTree (Int, a)) [STATE (Int, Int)]
276− -> { [STATE (Int, Int)] } Eff (BTree (Int, a))
278Doing this, however, ties the two states together throughout (as well
277Doing this, however, ties the two states together throughout (as well
279as not indicating which integer is which). It would be nice to be able
278as not indicating which integer is which). It would be nice to be able
@@ -288,9 +287,9 @@ leaves and update the tag separately, by labelling them as follows:
289.. code-block:: idris
288.. code-block:: idris
291− treeTagAux : BTree a
290+ treeTagAux : BTree a -> Eff (BTree (Int, a))
292− -> {['Tag ::: STATE Int,
291+ ['Tag ::: STATE Int,
293− 'Leaves ::: STATE Int]} Eff (BTree (Int, a))
292+ 'Leaves ::: STATE Int]
295The ``:::`` operator allows an arbitrary label to be given to an
294The ``:::`` operator allows an arbitrary label to be given to an
296effect. This label can be any type—it is simply used to identify an
295effect. This label can be any type—it is simply used to identify an
@@ -320,7 +319,7 @@ applying a function to the current state.
321.. code-block:: idris
320.. code-block:: idris
323− update : (x -> x) -> { [STATE x] } Eff ()
322+ update : (x -> x) -> Eff () [STATE x]
325Finally, our top level ``treeTag`` function now returns a pair of the
324Finally, our top level ``treeTag`` function now returns a pair of the
326number of leaves, and the new tree. Resources for labelled effects are
325number of leaves, and the new tree. Resources for labelled effects are
@@ -339,8 +338,7 @@ To summarise, we have:
340- ``:::`` to convert an effect to a labelled effect.
339- ``:::`` to convert an effect to a labelled effect.
342−- ``:-`` to convert an effectful operation to a labelled effectful
341+- ``:-`` to convert an effectful operation to a labelled effectful operation.
345- ``:=`` to initialise a resource for a labelled effect.
343- ``:=`` to initialise a resource for a labelled effect.
@@ -350,7 +348,7 @@ only for the situation where available effects are not updated):
350.. code-block:: idris
348.. code-block:: idris
352 (:::) : lbl -> EFFECT -> EFFECT
350 (:::) : lbl -> EFFECT -> EFFECT
353− (:-) : (l : lbl) -> { [x] } Eff a -> { [l ::: x] } Eff a
351+ (:-) : (l : lbl) -> Eff a [x] -> Eff a [l ::: x]
354 (:=) : (l : lbl) -> res -> LRes l res
352 (:=) : (l : lbl) -> res -> LRes l res
356Here, ``LRes`` is simply the resource type associated with a labelled
354Here, ``LRes`` is simply the resource type associated with a labelled
@@ -367,7 +365,7 @@ immediately. The following program returns the length of the
368.. code-block:: idris
366.. code-block:: idris
370− stateLength : { [STATE String] } Eff Nat
368+ stateLength : Eff Nat [STATE String]
371 stateLength = do x <- get
369 stateLength = do x <- get
372 pure (length x)
370 pure (length x)
@@ -377,7 +375,7 @@ this. The above program can be written instead as:
378.. code-block:: idris
376.. code-block:: idris
380− stateLength : { [STATE String] } Eff Nat
378+ stateLength : Eff Nat [STATE String]
381 stateLength = pure (length !get)
379 stateLength = pure (length !get)
383The notation ``!expr`` means that the expression ``expr`` should be
381The notation ``!expr`` means that the expression ``expr`` should be
@@ -386,7 +384,7 @@ evaluated and then implicitly bound. Conceptually, we can think of
387.. code-block:: idris
385.. code-block:: idris
389− (!) : { xs } Eff a -> a
387+ (!) : Eff a xs -> a
391Note, however, that it is not really a function, merely syntax! In
389Note, however, that it is not really a function, merely syntax! In
392practice, a subexpression ``!expr`` will lift ``expr`` as high as
390practice, a subexpression ``!expr`` will lift ``expr`` as high as
@@ -411,22 +409,22 @@ is lifted to:
411 g' <- g y' x'
409 g' <- g y' x'
414−Syntactic Sugar and ``Eff``
412+The Type ``Eff``
415−===========================
413+================
417−By now, you may be wondering about the syntax we are using for
415+Underneath, ``Eff`` is an overloaded function which translates to an
418−``Eff``, because it doesn’t look like a normal type! (If not, you may
416+underlying type ``EffM``:
419−safely skip this section and return to it later.) In fact, the type of
420−``Eff`` is the following:
422.. code-block:: idris
418.. code-block:: idris
424− Eff : (x : Type) ->
420+ EffM : (m : Type -> Type) -> (t : Type)
425− List EFFECT -> (x -> List EFFECT) -> Type
422+ -> (t -> List EFFECT) -> Type
427This is more general than the types we have been writing so far. It is
424This is more general than the types we have been writing so far. It is
425+parameterised over an underying computation context ``m``, a
428−parameterised over a result type ``x``, as we have already seen, but
426+result type ``t`` as we have already seen, as well as a ``List EFFECT`` and a
429−also a ``List EFFECT`` and a function type ``x -> List EFFECT``.
427+function type ``t -> List EFFECT``.
431These additional parameters are the list of *input* effects, and a
429These additional parameters are the list of *input* effects, and a
432list of *output* effects, computed from the result of an effectful
430list of *output* effects, computed from the result of an effectful
@@ -435,8 +433,7 @@ of effects available! This is a particularly powerful idea, and we
435will see its consequences in more detail later. Some examples of
433will see its consequences in more detail later. Some examples of
436operations which can change the set of available effects are:
434operations which can change the set of available effects are:
438−- Updating a state containing a dependent type (for example adding an
436+- Updating a state containing a dependent type (for example adding an element to a vector).
439− element to a vector).
441- Opening a file for reading is an effect, but whether the file really
438- Opening a file for reading is an effect, but whether the file really
442 *is* open afterwards depends on whether the file was successfully
439 *is* open afterwards depends on whether the file was successfully
@@ -445,19 +442,25 @@ operations which can change the set of available effects are:
445- Closing a file means that reading from the file should no longer be
442- Closing a file means that reading from the file should no longer be
446 possible.
443 possible.
448−While powerful, this can make uses of the ``Eff`` type hard to read.
445+While powerful, this can make uses of the ``EffM`` type hard to read.
449−Therefore, the library provides syntactic sugar which is translated
446+Therefore the library provides an overloaded function ``Eff``
450−such that:
447+There are the following three versions:
452.. code-block:: idris
449.. code-block:: idris
454− { xs } Eff a
451+ SimpleEff.Eff : (t : Type) -> (input_effs : List EFFECT) -> Type
452+ TransEff.Eff : (t : Type) -> (input_effs : List EFFECT) ->
453+ (output_effs : List EFFECT) -> Type
454+ DepEff.Eff : (t : Type) -> (input_effs : List EFFECT) ->
455+ (output_effs_fn : x -> List EFFECT) -> Type
456−is expanded to
457+So far, we have used only the first version, ``SimpleEff.Eff``, which
458+is defined as follows:
458.. code-block:: idris
460.. code-block:: idris
460− Eff a xs (\_ => xs)
462+ Eff : (x : Type) -> (es : List EFFECT) -> Type
463+ Eff x es = {m : Type -> Type} -> EffM m x es (\v => es)
462i.e. the set of effects remains the same on output. This suffices for
465i.e. the set of effects remains the same on output. This suffices for
463the ``STATE`` example we have seen so far, and for many useful
466the ``STATE`` example we have seen so far, and for many useful
@@ -467,19 +470,19 @@ with the expanded type:
467.. code-block:: idris
470.. code-block:: idris
469 treeTagAux : BTree a ->
472 treeTagAux : BTree a ->
470− Eff (BTree (Int, a)) [STATE Int] (\x => [STATE Int])
473+ EffM m (BTree (Int, a)) [STATE Int] (\x => [STATE Int])
472Later, we will see programs which update effects:
475Later, we will see programs which update effects:
474.. code-block:: idris
477.. code-block:: idris
476− { xs ==> xs' } Eff a
479+ Eff a xs xs'
478which is expanded to
481which is expanded to
480.. code-block:: idris
483.. code-block:: idris
482− Eff a xs (\_ => xs')
485+ EffM m a xs (\_ => xs')
484i.e. the set of effects is updated to ``xs’`` (think of a transition
487i.e. the set of effects is updated to ``xs’`` (think of a transition
485in a state machine). There is, for example, a version of ``put`` which
488in a state machine). There is, for example, a version of ``put`` which
@@ -487,22 +490,27 @@ updates the type of the state:
488.. code-block:: idris
491.. code-block:: idris
490− putM : y -> { [STATE x] ==> [STATE y] } Eff ()
493+ putM : y -> Eff () [STATE x] [STATE y]
492Also, we have:
495Also, we have:
494.. code-block:: idris
497.. code-block:: idris
496− { xs ==> {res} xs' } Eff a
499+ Eff t xs (\res => xs')
498which is expanded to
501which is expanded to
500.. code-block:: idris
503.. code-block:: idris
502− Eff a xs (\res => xs')
505+ EffM m t xs (\res => xs')
504i.e. the set of effects is updated according to the result of the
507i.e. the set of effects is updated according to the result of the
505−operation ``res``.
508+operation ``res``, of type ``t``.
510+Parameterising ``EffM`` over an underlying computation context allows us
511+to write effectful programs which are specific to one context, and in some
512+cases to write programs which *extend* the list of effects available using
513+the ``new`` function, though this is beyond the scope of this tutorial.
507.. [1] The earlier paper [3]_ describes the essential implementation
515.. [1] The earlier paper [3]_ describes the essential implementation
508 details, although the library presented there is an earlier version
516 details, although the library presented there is an earlier version