1 people like it.
Like the snippet!
Monad Bind 3 of 3
After watching this clip (http://www.youtube.com/watch?v=ZhuHCtR3xq8) on Youtube featuring Brian Beckman I wanted to try to sketch Brian's main argument that Monads' main purpose is function composition.
I will post my sketch to http://rodhern.wordpress.com/2014/02/ .
These snippets are the companion examples to the blog post.
1:
2:
|
// Script example (3 of 3) for Monad blog post
// at http://rodhern.wordpress.com/2014/02/
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
|
type M<'V> =
{
Value: 'V
LogMessages: string list
}
with
static member StaticReturn v = { Value= v; LogMessages= [] }
static member StaticBind (mt: M<'a>) (fn: 'a -> M<'b>) =
let result = fn mt.Value
let newmessage = sprintf ("Passing value %+A") mt.Value
let logmessages = result.LogMessages @ (newmessage :: mt.LogMessages)
{ Value= result.Value; LogMessages= logmessages }
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
|
/// A shorter name for M.StaticReturn.
/// Turning a variable of type 'a into M<'a> .
let ret x = M<_>.StaticReturn x
/// Turning a function with signature 'a -> 'b into M<'a> -> M<'b> .
let package fn mt = M<_>.StaticBind mt (fn >> ret)
/// The builder type may be an empty class like this one.
/// Often the builder instance is really nothing more than
/// a syntactic requirement.
type ComputationExpressionBuilderType () =
member public self.Return v = M<_>.StaticReturn v
member public self.Bind (mt, fn) = M<_>.StaticBind mt fn
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
|
type A = int
type B = float
type C = DateTime
type D = string
type R = M<A>
type S = M<B>
type T = M<C>
type U = M<D>
|
1:
2:
3:
|
let f (noWeeks: A): B = float (7 * noWeeks)
let g (noDays: B): C = today.AddDays noDays
let h (date: C): D = date.ToShortDateString ()
|
1:
2:
3:
|
let pf: R -> S = package f
let pg: S -> T = package g
let ph: T -> U = package h
|
1:
2:
|
let fghOne: R -> U = compose(compose(pf, pg), ph)
let fghTwo: R -> U = compose(pf, compose(pg, ph))
|
1:
2:
|
let fghOneResult = fghOne (ret myInputParam)
let fghTwoResult = fghTwo (ret myInputParam)
|
1:
2:
3:
4:
|
let Mx: R = ret myInputParam
let Mf: A -> S = f >> M<_>.StaticReturn
let Mg: B -> T = g >> M<_>.StaticReturn
let Mh: C -> U = h >> M<_>.StaticReturn
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
|
let builder = new ComputationExpressionBuilderType ()
let result =
builder {
let! a = Mx
let! b = Mf a
let! c = Mg b
let! d = Mh c
return d
}
|
type M<'V> =
{Value: 'V;
LogMessages: string list;}
static member StaticBind : mt:M<'a> -> fn:('a -> M<'b>) -> M<'b>
static member StaticReturn : v:'a -> M<'a>
Full name: Script.M<_>
In this example, as is often the case, the Monad, M<'V>,
is a container for, 'V, the value if interest.
M.Value: 'V
M.LogMessages: string list
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
static member M.StaticReturn : v:'a -> M<'a>
Full name: Script.M`1.StaticReturn
val v : 'a
static member M.StaticBind : mt:M<'a> -> fn:('a -> M<'b>) -> M<'b>
Full name: Script.M`1.StaticBind
val mt : M<'a>
val fn : ('a -> M<'b>)
val result : M<'b>
M.Value: 'a
val newmessage : string
val sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val logmessages : string list
M.Value: 'b
val ret : x:'a -> M<'a>
Full name: Script.ret
A shorter name for M.StaticReturn.
Turning a variable of type 'a into M<'a> .
val x : 'a
val package : fn:('a -> 'b) -> mt:M<'a> -> M<'b>
Full name: Script.package
Turning a function with signature 'a -> 'b into M<'a> -> M<'b> .
val fn : ('a -> 'b)
Multiple items
type ComputationExpressionBuilderType =
new : unit -> ComputationExpressionBuilderType
member Bind : mt:M<'a> * fn:('a -> M<'b>) -> M<'b>
member Return : v:'c -> M<'c>
Full name: Script.ComputationExpressionBuilderType
The builder type may be an empty class like this one.
Often the builder instance is really nothing more than
a syntactic requirement.
--------------------
new : unit -> ComputationExpressionBuilderType
val self : ComputationExpressionBuilderType
member ComputationExpressionBuilderType.Return : v:'c -> M<'c>
Full name: Script.ComputationExpressionBuilderType.Return
val v : 'c
member ComputationExpressionBuilderType.Bind : mt:M<'a> * fn:('a -> M<'b>) -> M<'b>
Full name: Script.ComputationExpressionBuilderType.Bind
type A = int
Full name: Script.A
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type B = float
Full name: Script.B
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
type C = DateTime
Full name: Script.C
Multiple items
type DateTime =
struct
new : ticks:int64 -> DateTime + 10 overloads
member Add : value:TimeSpan -> DateTime
member AddDays : value:float -> DateTime
member AddHours : value:float -> DateTime
member AddMilliseconds : value:float -> DateTime
member AddMinutes : value:float -> DateTime
member AddMonths : months:int -> DateTime
member AddSeconds : value:float -> DateTime
member AddTicks : value:int64 -> DateTime
member AddYears : value:int -> DateTime
...
end
Full name: System.DateTime
--------------------
DateTime()
(+0 other overloads)
DateTime(ticks: int64) : unit
(+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
(+0 other overloads)
type D = string
Full name: Script.D
type R = M<A>
Full name: Script.R
type S = M<B>
Full name: Script.S
type T = M<C>
Full name: Script.T
type U = M<D>
Full name: Script.U
val f : noWeeks:A -> B
Full name: Script.f
val noWeeks : A
val g : noDays:B -> C
Full name: Script.g
val noDays : B
val today : DateTime
Full name: Script.today
Today's date and time for use in examples below.
DateTime.AddDays(value: float) : DateTime
val h : date:C -> D
Full name: Script.h
val date : C
DateTime.ToShortDateString() : string
val pf : (R -> S)
Full name: Script.pf
val pg : (S -> T)
Full name: Script.pg
val ph : (T -> U)
Full name: Script.ph
val fghOne : (R -> U)
Full name: Script.fghOne
val compose : fun1:('a -> 'b) * fun2:('b -> 'c) -> arg:'a -> 'c
Full name: Script.compose
Our good old compose function from the first example
val fghTwo : (R -> U)
Full name: Script.fghTwo
val fghOneResult : U
Full name: Script.fghOneResult
val myInputParam : int
Full name: Script.myInputParam
The test parameter I will use is "2" as in "two weeks from now".
val fghTwoResult : U
Full name: Script.fghTwoResult
val Mx : R
Full name: Script.Mx
val Mf : (A -> S)
Full name: Script.Mf
val Mg : (B -> T)
Full name: Script.Mg
val Mh : (C -> U)
Full name: Script.Mh
val builder : ComputationExpressionBuilderType
Full name: Script.builder
By the construction of the syntax the builder must be an instance
of the builder type. The static methods will not do by themselves.
val result : M<D>
Full name: Script.result
val a : A
val b : B
val c : C
val d : D
More information