Multistep implementation of the Resumable monad
This module implements the multistep implementation of the resumable monad where the resumable expression is encoded as a mapping from the trace history type 'h to the expression's return type 't.
This contrasts with the implementation from the original article
where the encoding type 'h -> 'h * Option<'t>
represents a single state transition. That is a function mapping the existing
trace history to the updated history after taking a single step in the computation.
(i.e. advancing the computation to the next caching point).
The original encoding generates larger types but provides a clean separation between the definition of the resumable expression monad and the mechanism used for evaluation and for caching/persistence of the trace history.
The 'mulistep' encoding, defined in the present module, generates smaller types but requires stronger coupling between the definition of the monadic constructs and the execution and caching/persistence engine.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: |
|
The next type we define is not theoretically required to implement the resumable monad,
we introduce it solely to simplify the type encoding of caching points for large resumable expression.
It allows us to eliminate unneeded occurrences of option unit
in the type encoding 'h
of large resumable expressions.
The adverse effect is that we need to define multiple version of the bind monadic operators
for each possible combination of the two Resumable
type variations: Resumable<'h, 't>
and Resumable<'t>
(If the static constraint not ('h :> unit)
could be expressed in F# this would not be needed).
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: |
|
We can now declare the computational expression resumable { ... }
definining
all the syntactic sugar for the monadic operators defined in ResumableBuilder
.
1:
|
|
Examples
For usage examples of the resumable monad see the Examples page
Acknowledgement
I shared my original article on the resumable monad with Tomas Petricek who gave intersting feedback and in particular clarified the connection with the reader monad in an F# snippet. The enconding used in the mulitsep resumable monad is the same as the one used in Tomas's snippet however the caching here is performed within the definition of the bind operator as opposed to an external function.
from ResumableMonad
Multistep resumable monad where a resumable expression is encoded as a
mapping from the trace history type 'h to the expression's return type 't.
union case Resumable.Resumable: ('h -> 't) -> Resumable<'h,'t>
--------------------
type Resumable<'t> =
| Spawnable of (unit -> 't)
member resume : (unit -> 't)
Full name: ResumableMonad.Multipstep.Resumable<_>
A resumable computation of type `'t` with no caching point.
--------------------
type Resumable<'h,'t> =
| Resumable of ('h -> 't)
member initial : obj
member resume : h:'h -> 't
Full name: ResumableMonad.Multipstep.Resumable<_,_>
A resumable computation returning a result of type `'t` with a sequence of
caching points encoded by type `'h`.
- 'h is a type generated from the monadic expression to encode the history of caching points in the
resumable expression. It consists of nested tuples with base elements of type 'a option for each
caching point in the computation.
- 't is the returned type of the computation
Full name: ResumableMonad.Multipstep.Resumable`2.resume
Full name: ResumableMonad.Multipstep.Resumable`2.initial
Returns the empty history (no caching point are initialized)
Full name: Microsoft.FSharp.Core.unit
Full name: ResumableMonad.Multipstep.Resumable`1.resume
Full name: ResumableMonad.Multipstep.getOrEvaluate
Return the encapsulated value if present otherwise return the result of the specified `evaluate` function
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
type ResumableBuilder =
new : unit -> ResumableBuilder
member Bind : f:Resumable<'u,'a> * g:('a -> Resumable<'v,'b>) -> Resumable<('a option * 'u * 'v),'b>
member Bind : f:Resumable<'u,'a> * g:('a -> Resumable<'b>) -> Resumable<('a option * 'u),'b>
member Bind : f:Resumable<'a> * g:('a -> Resumable<'v,'b>) -> Resumable<('a option * 'v),'b>
member Bind : f:Resumable<'a> * g:('a -> Resumable<'b>) -> Resumable<'a option,'b>
member BindNoCache : f:Resumable<'a> * g:('a -> Resumable<'b>) -> Resumable<'b>
member Combine : p1:Resumable<'u,unit> * p2:Resumable<'v,'b> -> Resumable<('u * 'v),'b>
member Combine : p1:Resumable<unit> * p2:Resumable<'b> -> Resumable<'b>
member Delay : f:(unit -> Resumable<'h,'t>) -> Resumable<'h,'t>
member Delay : f:(unit -> Resumable<'t>) -> Resumable<'t>
...
Full name: ResumableMonad.Multipstep.ResumableBuilder
The syntax builder for the Resumable monadic syntax
--------------------
new : unit -> ResumableBuilder
Full name: ResumableMonad.Multipstep.ResumableBuilder.Zero
Full name: ResumableMonad.Multipstep.ResumableBuilder.Return
Full name: ResumableMonad.Multipstep.ResumableBuilder.Delay
Full name: ResumableMonad.Multipstep.ResumableBuilder.Delay
Full name: ResumableMonad.Multipstep.ResumableBuilder.Bind
Full name: ResumableMonad.Multipstep.ResumableBuilder.Bind
Full name: ResumableMonad.Multipstep.ResumableBuilder.Bind
Full name: ResumableMonad.Multipstep.ResumableBuilder.Bind
Full name: ResumableMonad.Multipstep.ResumableBuilder.BindNoCache
Full name: ResumableMonad.Multipstep.ResumableBuilder.Combine
Full name: ResumableMonad.Multipstep.ResumableBuilder.Combine
Full name: ResumableMonad.Multipstep.ResumableBuilder.While
Full name: ResumableMonad.Multipstep.resumable