Skip to content

Commit 54960d7

Browse files
committed
+ Free monad docs
1 parent 56beb47 commit 54960d7

File tree

1 file changed

+107
-3
lines changed

1 file changed

+107
-3
lines changed

docsrc/content/type-free.fsx

+107-3
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,121 @@
33
// it to define helpers that you do not want to show in the documentation.
44
#r @"../../src/FSharpPlus/bin/Release/netstandard2.0/FSharpPlus.dll"
55
(**
6-
TO-DO Add some docs here !
7-
=========================
6+
Free<'Functor<'T>, 'T>
7+
======================
8+
9+
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+
820
921
Examples
1022
--------
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+
1126
*)
1227

28+
29+
1330
(**
1431
```f#
1532
#r @"nuget: FSharpPlus"
1633
```
1734
*)
1835

19-
open FSharpPlus
36+
open System
37+
open FSharpPlus
38+
open FSharpPlus.Data
39+
40+
41+
type CommandLineInstruction<'t> =
42+
| ReadLine of (string -> 't)
43+
| WriteLine of string * 't
44+
with static member Map (x, f) =
45+
match x with
46+
| ReadLine g -> ReadLine (f << g)
47+
| WriteLine (s, g) -> WriteLine (s, f g)
48+
49+
let readLine = Free.liftF (ReadLine id)
50+
let writeLine s = Free.liftF (WriteLine (s, ()))
51+
52+
53+
let rec interpretCommandLine = 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 rec readQuantity = 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 rec readDate = 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+
let readName = monad {
79+
do! writeLine "Please enter your name:"
80+
return! readLine }
81+
82+
let readEmail = monad {
83+
do! writeLine "Please enter your email address:"
84+
return! readLine }
85+
86+
87+
type Reservation = {
88+
Date : DateTimeOffset
89+
Name : string
90+
Email : string
91+
Quantity : int }
92+
with static member Create (Quantity, Date, Name, Email) = { Date = Date; Name = Name; Email = Email; Quantity = Quantity }
93+
94+
let readReservationRequest =
95+
curryN Reservation.Create
96+
<!> readQuantity
97+
<*> readDate
98+
<*> readName
99+
<*> readEmail
100+
101+
102+
103+
let mainFunc () =
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.
122+
123+
*)

0 commit comments

Comments
 (0)