5 people like it.

This is a reader monad, whit the difference that multiple reads access different parts of the state. This is done by building up a tuple (in the bind operator) that represents different parts of the state that can be accessed by different parts of the computation.

 ``` 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: ``` ``````/// A reader monad is a computation that takes a state 'S and produces a value 'T /// /// In the usual reader monad, we would have `unit : T -> Reader` and /// `bind : (T1 -> Reader) -> Reader -> Reader` but /// we're going to do things a bit differently here and the state we read /// is going to be composed as a tuple of things that are read by the individual /// computations composed by bind. type Reader<'S, 'T> = Reader of ('S -> 'T) /// The unit operation does not read any state and so it produces `Reader` let unit v = Reader(fun () -> v) /// The bind operation takes `Reader` and a function that reads another /// part of the state `T1 -> Reader` and produces a reader that reads /// both state values (in a tuple) so that's `Reader` let bind f (Reader(g)) = Reader(fun (a, b) -> let v = g a let (Reader h) = f v h b) /// Defines the computation builder - add `Delay` so that we can delay things! type ReaderBuilder() = member x.Return(v) = unit v member x.Bind(v, f) = bind f v member x.Delay(f) = Reader (fun s -> let (Reader h) = f () h s ) let reader = ReaderBuilder() /// A function that takes a computation written as `Reader`. It builds a new /// computation of type `Reader*S, T>` that attempts to read a cached result /// of type T from the state - if it is there, we just return it, otherwise we run /// the computation provided as an argument to actually compute the value. let cache (Reader(f)) = (Reader(fun (v1, v2) -> match v1 with | None -> f v2 | Some v -> v)) /// Returns `n` and prints string to log what's happening let read s n = reader { printfn "Reading: %s" s return n } let m = reader { // The following two are only run if the value is not already available let! a = cache <| read "A" 1 let! b = cache <| read "B" 2 // The following read is done always (not accesses the state) let! c = read "C" 3 return a + b + c } let (Reader f) = m f ((None, ()), ((None, ()), ((), ()))) f ((Some 1, ()), ((None, ()), ((), ()))) f ((None, ()), ((Some 2, ()), ((), ()))) f ((Some 1, ()), ((Some 2, ()), ((), ()))) ``````
Multiple items

--------------------
type Reader<'S,'T> = | Reader of ('S -> 'T)

A reader monad is a computation that takes a state 'S and produces a value 'T

In the usual reader monad, we would have `unit : T -> Reader<S, T>` and
`bind : (T1 -> Reader<S, T2>) -> Reader<S, T1> -> Reader<S, T2>` but
we're going to do things a bit differently here and the state we read
is going to be composed as a tuple of things that are read by the individual
computations composed by bind.
Multiple items
val unit : v:'a -> Reader<unit,'a>

Full name: Script.unit

The unit operation does not read any state and so it produces `Reader<unit, T>`

--------------------
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
val v : 'a
val bind : f:('a -> Reader<'b,'c>) -> Reader<'d,'a> -> Reader<('d * 'b),'c>

Full name: Script.bind

The bind operation takes `Reader<S1, T1>` and a function that reads another
part of the state `T1 -> Reader<S2, T2>` and produces a reader that reads
both state values (in a tuple) so that's `Reader<S1*S2, T2>`
val f : ('a -> Reader<'b,'c>)
val g : ('d -> 'a)
val a : 'd
val b : 'b
val h : ('b -> 'c)
Multiple items
new : unit -> ReaderBuilder
member Bind : v:Reader<'c,'d> * f:('d -> Reader<'e,'f>) -> Reader<('c * 'e),'f>
member Delay : f:(unit -> Reader<'a,'b>) -> Reader<'a,'b>
member Return : v:'g -> Reader<unit,'g>

Defines the computation builder - add `Delay` so that we can delay things!

--------------------
new : unit -> ReaderBuilder
val x : ReaderBuilder

val v : 'g

val v : Reader<'c,'d>
val f : ('d -> Reader<'e,'f>)

val f : (unit -> Reader<'a,'b>)
val s : 'a
val h : ('a -> 'b)

val cache : Reader<'a,'b> -> Reader<('b option * 'a),'b>

Full name: Script.cache

A function that takes a computation written as `Reader<S, T>`. It builds a new
computation of type `Reader<option<T>*S, T>` that attempts to read a cached result
of type T from the state - if it is there, we just return it, otherwise we run
the computation provided as an argument to actually compute the value.
val f : ('a -> 'b)
val v1 : 'b option
val v2 : 'a
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val v : 'b
val read : s:string -> n:'a -> Reader<unit,'a>

Returns `n` and prints string to log what's happening
val s : string
val n : 'a
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val m : Reader<((int option * unit) * ((int option * unit) * (unit * unit))),int>

Full name: Script.m
val a : int
val b : int
val c : int
val f : ((int option * unit) * ((int option * unit) * (unit * unit)) -> int)

Full name: Script.f