You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This type is an implementation of the [Free Monad](https://www.google.com/search?q=free+monad) which is generic to any [Functor](abstraction-functor.html).
10
+
11
+
The Free Monad is used typically to describe a pure program at high level and separately write different interpreters for it.
12
+
13
+
Related Types
14
+
-------------
15
+
16
+
- [Coproduct](type-coproduct.html): A [Functor](abstraction-functor.html) used in conjunction with the Free Monad to combine different instruction sets.
17
+
18
+
19
+
8
20
9
21
Examples
10
22
--------
23
+
24
+
Free monad-interpreter in F# from [Mark Seemann's blog](https://blog.ploeh.dk/2017/07/17/a-pure-command-line-wizard) but encoded with Free.
25
+
11
26
*)
12
27
28
+
29
+
13
30
(**
14
31
```f#
15
32
#r @"nuget: FSharpPlus"
16
33
```
17
34
*)
18
35
19
-
openFSharpPlus
36
+
openSystem
37
+
openFSharpPlus
38
+
openFSharpPlus.Data
39
+
40
+
41
+
typeCommandLineInstruction<'t>=
42
+
| ReadLine of(string->'t)
43
+
| WriteLine ofstring*'t
44
+
withstatic memberMap(x,f)=
45
+
match x with
46
+
| ReadLine g -> ReadLine (f << g)
47
+
| WriteLine (s, g)-> WriteLine (s, f g)
48
+
49
+
letreadLine= Free.liftF (ReadLine id)
50
+
letwriteLine s = Free.liftF (WriteLine (s,()))
51
+
52
+
53
+
let recinterpretCommandLine= Free.run >>function
54
+
| Pure x -> x
55
+
| Roll (ReadLine next)-> Console.ReadLine ()|> next |> interpretCommandLine
56
+
| Roll (WriteLine (s, next))->
57
+
Console.WriteLine s
58
+
next |> interpretCommandLine
59
+
60
+
let recreadQuantity= monad {
61
+
do! writeLine "Please enter number of diners:"
62
+
let!l= readLine
63
+
match tryParse l with
64
+
| Some dinerCount ->return dinerCount
65
+
| None ->
66
+
do! writeLine "Not an integer."
67
+
return! readQuantity }
68
+
69
+
let recreadDate= monad {
70
+
do! writeLine "Please enter your desired date:"
71
+
let!l= readLine
72
+
match DateTimeOffset.TryParse l with
73
+
|true, dt ->return dt
74
+
|_->
75
+
do! writeLine "Not a date."
76
+
return! readDate }
77
+
78
+
letreadName= monad {
79
+
do! writeLine "Please enter your name:"
80
+
return! readLine }
81
+
82
+
letreadEmail= monad {
83
+
do! writeLine "Please enter your email address:"
84
+
return! readLine }
85
+
86
+
87
+
typeReservation={
88
+
Date :DateTimeOffset
89
+
Name :string
90
+
Email :string
91
+
Quantity :int }
92
+
withstatic memberCreate(Quantity,Date,Name,Email)={ Date = Date; Name = Name; Email = Email; Quantity = Quantity }
93
+
94
+
letreadReservationRequest=
95
+
curryN Reservation.Create
96
+
<!> readQuantity
97
+
<*> readDate
98
+
<*> readName
99
+
<*> readEmail
100
+
101
+
102
+
103
+
letmainFunc()=
104
+
readReservationRequest
105
+
>>=(writeLine <<(sprintf "%A"))
106
+
|> interpretCommandLine
107
+
0
108
+
109
+
110
+
(**
111
+
More reading
112
+
------------
113
+
114
+
- Highly recommended Matt Thornton's blog [Grokking Free monads](https://dev.to/choc13/grokking-free-monads-9jd) and [Interpreting Free Monads](https://dev.to/choc13/interpreting-free-monads-3l3e).
115
+
It contains examples using F#+ and an explanation from scratch.
116
+
117
+
- Mark Seemann's blog has an [article series](https://blog.ploeh.dk/2017/06/27/pure-times/) which ends
118
+
up describing Free Monads although he doesn't use F#+ and therefore either repeats boilerplate code or switches to Haskell.
119
+
Anyways some code from those series (like the above fragment) can be found in [our test suite for Free](https://github.com/fsprojects/FSharpPlus/blob/master/tests/FSharpPlus.Tests/Free.fs) simplified using Free and Coproduct types.
120
+
121
+
- Scott Wlaschin's [13 ways of looking at a turtle](https://fsharpforfunandprofit.com/posts/13-ways-of-looking-at-a-turtle) is also a series which ends up defining a Free Monad, without using F#+ but with boilerplate code instead.
0 commit comments