3 people like it.
Like the snippet!
Simple builder example: Nullable
Simple Computational expressions / monad / builder -example, using .NET Nullable as demo.
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:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
|
module BuilderExample
open System
//------------------------------------------------
//Example 1: First try, just return
type Nullable1Builder() =
member this.Return(x) = Nullable(x)
let myNullable1 = Nullable1Builder()
let MakeNullable =
myNullable1{
let a = 5 + 1
return a // calls builders Return(x)
}
//val test : Nullable<int> = 6
//------------------------------------------------
//Example 2: nullable { ... } with combining functionality
type Nullable2Builder() =
let hasValue (a:Nullable<'a>) = a.HasValue
member t.Return(x) = Nullable(x)
member t.Bind(x, rest) =
match hasValue x with
| false -> System.Nullable()
| true -> rest(x.Value)
let nullable = Nullable2Builder()
let test =
nullable{
let! a = System.Nullable(4) // Call Bind
let! b = System.Nullable(5) // Call Bind
//Inside computation expression(/monad): easy programming without Nullable-worries:
let mult = a * b
let sum = mult + 1
return sum //Call Return
}
//val test : Nullable<int> = 16
//------------------------------------------------------------------------------
// using e.g.
// let! b = System.Nullable()
// would cause to return:
// val test : System.Nullable()
// own { ...} syntax is made with implementing Builder-class
// and (some of) the "interface" members
//------------------------------------------------------------------------------
// Some optional technical details:
// Actual stack in example2, you don't have to care about this:
// nullable.Bind(Nullable(3), (fun res1 ->
// nullable.Bind(Nullable(5), (fun res2 ->
// nullable.Let(res1*res2, (fun res3 ->
// nullable.Let(res3+1, (fun res4 ->
// nullable.Return(res4)))))))))
//------------------------------------------------
// Further reading:
// Interface described in: http://msdn.microsoft.com/en-us/library/dd233182.aspx
// More info: http://blogs.msdn.com/b/dsyme/archive/2007/09/22/some-details-on-f-computation-expressions-aka-monadic-or-workflow-syntax.aspx
// Check also Reactive Extensions 2.0 with F# observe { ... }:
// https://github.com/panesofglass/FSharp.Reactive/blob/master/src/Observable.fs
// and: http://fssnip.net/tags/computation+builder and http://fssnip.net/tags/monad
//------------------------------------------------
//<just for intellisense>
type M<'T> = System.Collections.Generic.IEnumerable<'T>
type ImplementJustWhatYouWantBuilder =
//</just for intellisense>
// The builder methods are described in MSDN:
abstract member Bind: M<'T> * ('T -> M<'U>) -> M<'U> // Called for let! and do! in computation expressions.
abstract member Delay: (unit -> M<'T>) -> M<'T> // Wraps a computation expression as a function.
abstract member Return: 'T -> M<'T> // Called for return in computation expressions.
abstract member ReturnFrom: M<'T> -> M<'T> // Called for return! in computation expressions.
abstract member Run: M<'T> -> M<'T> // Executes a computation expression.
// or abstract member Run: M<'T> -> 'T // Executes a computation expression.
abstract member Combine: M<'T> * M<'T> -> M<'T> // Called for sequencing in computation expressions.
abstract member Combine: M<unit> * M<'T> -> M<'T> // Called for sequencing in computation expressions.
abstract member For: seq<'T> * ('T -> M<'U>) -> M<'U> // Called for for...do expressions in computation expressions.
// or abstract member For: seq<'T> * ('T -> M<'U>) -> seq<M<'U>> // Called for for...do expressions in computation expressions.
abstract member TryFinally: M<'T> * (unit -> unit) -> M<'T> // Called for try...finally expressions in computation expressions.
abstract member TryWith: M<'T> * (exn -> M<'T>) -> M<'T> // Called for try...with expressions in computation expressions.
abstract member Using: 'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable // Called for use bindings in computation expressions.
abstract member While: (unit -> bool) * M<'T> -> M<'T> // Called for while...do expressions in computation expressions.
abstract member Yield: 'T -> M<'T> // Called for yield expressions in computation expressions.
abstract member YieldFrom: M<'T> -> M<'T> // Called for yield! expressions in computation expressions.
abstract member Zero: unit -> M<'T> // Called for empty else branches of if...then expressions in computation expressions.
|
module BuilderExample
namespace System
Multiple items
type Nullable1Builder =
new : unit -> Nullable1Builder
member Return : x:'a -> Nullable<'a> (requires default constructor and value type and 'a :> ValueType)
Full name: BuilderExample.Nullable1Builder
--------------------
new : unit -> Nullable1Builder
val this : Nullable1Builder
member Nullable1Builder.Return : x:'a -> Nullable<'a> (requires default constructor and value type and 'a :> ValueType)
Full name: BuilderExample.Nullable1Builder.Return
val x : 'a (requires default constructor and value type and 'a :> ValueType)
Multiple items
type Nullable =
static member Compare<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> int
static member Equals<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> bool
static member GetUnderlyingType : nullableType:Type -> Type
Full name: System.Nullable
--------------------
type Nullable<'T (requires default constructor and value type and 'T :> ValueType)> =
struct
new : value:'T -> Nullable<'T>
member Equals : other:obj -> bool
member GetHashCode : unit -> int
member GetValueOrDefault : unit -> 'T + 1 overload
member HasValue : bool
member ToString : unit -> string
member Value : 'T
end
Full name: System.Nullable<_>
--------------------
Nullable()
Nullable(value: 'T) : unit
val myNullable1 : Nullable1Builder
Full name: BuilderExample.myNullable1
val MakeNullable : Nullable<int>
Full name: BuilderExample.MakeNullable
val a : int
Multiple items
type Nullable2Builder =
new : unit -> Nullable2Builder
member Bind : x:Nullable<'a> * rest:('a -> Nullable<'b>) -> Nullable<'b> (requires default constructor and value type and 'a :> ValueType and default constructor and value type and 'b :> ValueType)
member Return : x:'c -> Nullable<'c> (requires default constructor and value type and 'c :> ValueType)
Full name: BuilderExample.Nullable2Builder
--------------------
new : unit -> Nullable2Builder
val hasValue : (Nullable<'a> -> bool) (requires default constructor and value type and 'a :> ValueType)
val a : Nullable<'a> (requires default constructor and value type and 'a :> ValueType)
property Nullable.HasValue: bool
val t : Nullable2Builder
member Nullable2Builder.Return : x:'c -> Nullable<'c> (requires default constructor and value type and 'c :> ValueType)
Full name: BuilderExample.Nullable2Builder.Return
val x : 'c (requires default constructor and value type and 'c :> ValueType)
member Nullable2Builder.Bind : x:Nullable<'a> * rest:('a -> Nullable<'b>) -> Nullable<'b> (requires default constructor and value type and 'a :> ValueType and default constructor and value type and 'b :> ValueType)
Full name: BuilderExample.Nullable2Builder.Bind
val x : Nullable<'a> (requires default constructor and value type and 'a :> ValueType)
val rest : ('a -> Nullable<'b>) (requires default constructor and value type and 'a :> ValueType and default constructor and value type and 'b :> ValueType)
property Nullable.Value: 'a
val nullable : Nullable2Builder
Full name: BuilderExample.nullable
val test : Nullable<int>
Full name: BuilderExample.test
val b : int
val mult : int
val sum : int
type M<'T> = Collections.Generic.IEnumerable<'T>
Full name: BuilderExample.M<_>
namespace System.Collections
namespace System.Collections.Generic
type IEnumerable<'T> =
member GetEnumerator : unit -> IEnumerator<'T>
Full name: System.Collections.Generic.IEnumerable<_>
type ImplementJustWhatYouWantBuilder =
interface
abstract member Bind : M<'T> * ('T -> M<'U>) -> M<'U>
abstract member Combine : M<'T> * M<'T> -> M<'T>
abstract member Combine : M<unit> * M<'T> -> M<'T>
abstract member Delay : (unit -> M<'T>) -> M<'T>
abstract member For : seq<'T> * ('T -> M<'U>) -> M<'U>
abstract member Return : 'T -> M<'T>
abstract member ReturnFrom : M<'T> -> M<'T>
abstract member Run : M<'T> -> M<'T>
abstract member TryFinally : M<'T> * (unit -> unit) -> M<'T>
abstract member TryWith : M<'T> * (exn -> M<'T>) -> M<'T>
...
end
Full name: BuilderExample.ImplementJustWhatYouWantBuilder
abstract member ImplementJustWhatYouWantBuilder.Bind : M<'T> * ('T -> M<'U>) -> M<'U>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Bind
abstract member ImplementJustWhatYouWantBuilder.Delay : (unit -> M<'T>) -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Delay
type unit = Unit
Full name: Microsoft.FSharp.Core.unit
abstract member ImplementJustWhatYouWantBuilder.Return : 'T -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Return
abstract member ImplementJustWhatYouWantBuilder.ReturnFrom : M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.ReturnFrom
abstract member ImplementJustWhatYouWantBuilder.Run : M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Run
abstract member ImplementJustWhatYouWantBuilder.Combine : M<'T> * M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Combine
abstract member ImplementJustWhatYouWantBuilder.Combine : M<unit> * M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Combine
abstract member ImplementJustWhatYouWantBuilder.For : seq<'T> * ('T -> M<'U>) -> M<'U>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.For
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
abstract member ImplementJustWhatYouWantBuilder.TryFinally : M<'T> * (unit -> unit) -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.TryFinally
abstract member ImplementJustWhatYouWantBuilder.TryWith : M<'T> * (exn -> M<'T>) -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.TryWith
type exn = Exception
Full name: Microsoft.FSharp.Core.exn
abstract member ImplementJustWhatYouWantBuilder.Using : 'T * ('T -> M<'U>) -> M<'U> (requires 'U :> IDisposable)
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Using
type IDisposable =
member Dispose : unit -> unit
Full name: System.IDisposable
abstract member ImplementJustWhatYouWantBuilder.While : (unit -> bool) * M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.While
type bool = Boolean
Full name: Microsoft.FSharp.Core.bool
abstract member ImplementJustWhatYouWantBuilder.Yield : 'T -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Yield
abstract member ImplementJustWhatYouWantBuilder.YieldFrom : M<'T> -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.YieldFrom
abstract member ImplementJustWhatYouWantBuilder.Zero : unit -> M<'T>
Full name: BuilderExample.ImplementJustWhatYouWantBuilder.Zero
More information