3 people like it.

Alternative reader monad

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<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.
type Reader<'S, 'T> = Reader of ('S -> 'T)

/// The unit operation does not read any state and so it produces `Reader<unit, T>`
let unit v = Reader(fun () -> v)

/// 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>`
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<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.
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
union case Reader.Reader: ('S -> 'T) -> Reader<'S,'T>

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

Full name: Script.Reader<_,_>


 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
type ReaderBuilder =
  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>

Full name: Script.ReaderBuilder


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


--------------------
new : unit -> ReaderBuilder
val x : ReaderBuilder
member ReaderBuilder.Return : v:'g -> Reader<unit,'g>

Full name: Script.ReaderBuilder.Return
val v : 'g
member ReaderBuilder.Bind : v:Reader<'c,'d> * f:('d -> Reader<'e,'f>) -> Reader<('c * 'e),'f>

Full name: Script.ReaderBuilder.Bind
val v : Reader<'c,'d>
val f : ('d -> Reader<'e,'f>)
member ReaderBuilder.Delay : f:(unit -> Reader<'a,'b>) -> Reader<'a,'b>

Full name: Script.ReaderBuilder.Delay
val f : (unit -> Reader<'a,'b>)
val s : 'a
val h : ('a -> 'b)
val reader : ReaderBuilder

Full name: Script.reader
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>

Full name: Script.read


 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
Raw view New version

More information

Link:http://fssnip.net/tu
Posted:1 years ago
Author:Tomas Petricek
Tags: monads , reader , state