3
3
// it to define helpers that you do not want to show in the documentation.
4
4
5
5
#r @" ../../src/FSharpPlus/bin/Release/netstandard2.0/FSharpPlus.dll"
6
- #nowarn " 0058" // We need to cheat a bit with indentation here.
7
6
8
7
(**
9
8
Introducing FSharpPlus
@@ -20,12 +19,11 @@ Introducing FSharpPlus
20
19
#r @"nuget: FSharpPlus"
21
20
```
22
21
*)
23
- open FSharpPlus
24
-
25
- (**
26
- Ignore warnings about F# metadata if any.
27
22
23
+ (*** hide ***)
24
+ module [<AutoOpen>] E1 =
28
25
26
+ (**
29
27
Now we'll start with a quick overview of the features presented in F#+.
30
28
31
29
### Generic functions
@@ -36,33 +34,35 @@ here's an example with <code>map</code> ([fmap](https://wiki.haskell.org/Functor
36
34
37
35
*)
38
36
39
- map string [| 2 ; 3 ; 4 ; 5 |]
40
- // val it : string [] = [|"2"; "3"; "4"; "5"|]
37
+ open FSharpPlus
41
38
42
- map ((+) 9 ) ( Some 3 )
43
- // val it : int option = Some 12
39
+ map string [| 2 ; 3 ; 4 ; 5 |]
40
+ // val it : string [] = [|"2"; "3"; "4"; "5"|]
44
41
45
- open FSharpPlus.Data
42
+ map ((+) 9 ) ( Some 3 )
43
+ // val it : int option = Some 12
46
44
47
- map string ( NonEmptyList.create 2 [ 3 ; 4 ; 5 ])
48
- // val it : NonEmptyList<string> = {Head = "2"; Tail = ["3"; "4"; "5"];}
45
+ open FSharpPlus.Data
46
+
47
+ map string ( NonEmptyList.create 2 [ 3 ; 4 ; 5 ])
48
+ // val it : NonEmptyList<string> = {Head = "2"; Tail = ["3"; "4"; "5"];}
49
49
50
50
(**
51
51
They're also available for your own types as long as they contain the appropriated method with the expected signature
52
52
*)
53
53
54
54
55
- type Tree < 't > =
56
- | Tree of 't * Tree < 't > * Tree < 't >
57
- | Leaf of 't
58
- static member Map ( x : Tree < 'a >, f ) =
59
- let rec loop f = function
60
- | Leaf x -> Leaf ( f x)
61
- | Tree ( x, t1, t2) -> Tree ( f x, loop f t1, loop f t2)
62
- loop f x
63
-
64
- map ((*) 10 ) ( Tree( 6 , Tree( 2 , Leaf 1 , Leaf 3 ), Leaf 9 ))
65
- // val it : Tree<int> = Tree (60,Tree (20,Leaf 10,Leaf 30),Leaf 90)
55
+ type Tree < 't > =
56
+ | Tree of 't * Tree < 't > * Tree < 't >
57
+ | Leaf of 't
58
+ static member Map ( x : Tree < 'a >, f ) =
59
+ let rec loop f = function
60
+ | Leaf x -> Leaf ( f x)
61
+ | Tree ( x, t1, t2) -> Tree ( f x, loop f t1, loop f t2)
62
+ loop f x
63
+
64
+ map ((*) 10 ) ( Tree( 6 , Tree( 2 , Leaf 1 , Leaf 3 ), Leaf 9 ))
65
+ // val it : Tree<int> = Tree (60,Tree (20,Leaf 10,Leaf 30),Leaf 90)
66
66
67
67
(**
68
68
Generic functions may be seen as an exotic thing in F# that only saves a few key strokes (<code>map</code> instead of <code>List.map</code> or <code>Array.map</code>) still they allow you to reach a higher abstraction level, using ad-hoc polymorphism.
@@ -72,67 +72,70 @@ But more interesting is the use of operators. You can't prefix them with the mod
72
72
Here you have a ready-to-use generic bind operator: ``>>=``
73
73
*)
74
74
75
- let x = [ " hello" ; " " ; " world" ] >>= ( fun x -> Seq.toList x)
76
- // val x : char list = ['h'; 'e'; 'l'; 'l'; 'o'; ' '; 'w'; 'o'; 'r'; 'l'; 'd']
75
+ let x = [ " hello" ; " " ; " world" ] >>= ( fun x -> Seq.toList x)
76
+ // val x : char list = ['h'; 'e'; 'l'; 'l'; 'o'; ' '; 'w'; 'o'; 'r'; 'l'; 'd']
77
77
78
78
79
- let tryParseInt : string -> int option = tryParse
80
- let tryDivide x n = if n = 0 then None else Some ( x / n)
79
+ let tryParseInt : string -> int option = tryParse
80
+ let tryDivide x n = if n = 0 then None else Some ( x / n)
81
81
82
- let y = Some " 20" >>= tryParseInt >>= tryDivide 100
83
- // val y : int option = Some 5
82
+ let y = Some " 20" >>= tryParseInt >>= tryDivide 100
83
+ // val y : int option = Some 5
84
84
85
85
(**
86
86
You have also the Kleisli composition (fish) operator: ``>=>``
87
87
88
88
Which is becoming popular in F# after the [Railway Oriented Programming](https://www.google.ch/#q=railway+oriented+programming) tutorial series
89
89
*)
90
90
91
- let parseAndDivide100By = tryParseInt >=> tryDivide 100
91
+ let parseAndDivide100By = tryParseInt >=> tryDivide 100
92
92
93
- let parsedAndDivide100By20 = parseAndDivide100By " 20" // Some 5
94
- let parsedAndDivide100By0 ' = parseAndDivide100By " zero" // None
95
- let parsedAndDivide100By0 = parseAndDivide100By " 0" // None
93
+ let parsedAndDivide100By20 = parseAndDivide100By " 20" // Some 5
94
+ let parsedAndDivide100By0 ' = parseAndDivide100By " zero" // None
95
+ let parsedAndDivide100By0 = parseAndDivide100By " 0" // None
96
96
97
- let parseElement n = List.tryItem n >=> tryParseInt
98
- let parsedElement = parseElement 2 [ " 0" ; " 1" ; " 2" ]
97
+ let parseElement n = List.tryItem n >=> tryParseInt
98
+ let parsedElement = parseElement 2 [ " 0" ; " 1" ; " 2" ]
99
99
100
100
(**
101
101
But don't forget the above used operators are generic, so we can change the type of our functions and we get a different functionality for free:
102
102
*)
103
103
104
104
(*** hide ***)
105
- module E2 =
105
+ open FSharpPlus
106
+
107
+ (*** hide ***)
108
+ module E2 =
106
109
107
- let tryParseInt x : Choice < int , string > =
108
- match tryParse x with
109
- | Some x -> Choice1Of2 x
110
- | None -> Choice2Of2 ( " Failed to parse " + x)
110
+ let tryParseInt x : Choice < int , string > =
111
+ match tryParse x with
112
+ | Some x -> Choice1Of2 x
113
+ | None -> Choice2Of2 ( " Failed to parse " + x)
111
114
112
115
113
- let tryDivide x n =
114
- if n = 0 then Choice2Of2 " Can't divide by zero"
115
- else Choice1Of2 ( x / n)
116
+ let tryDivide x n =
117
+ if n = 0 then Choice2Of2 " Can't divide by zero"
118
+ else Choice1Of2 ( x / n)
116
119
117
120
(**
118
121
The test code remains unchanged, but we get a more interesting functionality
119
122
*)
120
123
121
- let parseAndDivide100By = tryParseInt >=> tryDivide 100
124
+ let parseAndDivide100By = tryParseInt >=> tryDivide 100
122
125
123
- let parsedAndDivide100By20 = parseAndDivide100By " 20" // Choice1Of2 5
124
- let parsedAndDivide100By0 ' = parseAndDivide100By " zero" // Choice2Of2 "Failed to parse zero"
125
- let parsedAndDivide100By0 = parseAndDivide100By " 0" // Choice2Of2 "Can't divide by zero"
126
+ let parsedAndDivide100By20 = parseAndDivide100By " 20" // Choice1Of2 5
127
+ let parsedAndDivide100By0 ' = parseAndDivide100By " zero" // Choice2Of2 "Failed to parse zero"
128
+ let parsedAndDivide100By0 = parseAndDivide100By " 0" // Choice2Of2 "Can't divide by zero"
126
129
127
130
128
131
(**
129
132
130
133
Also when working with combinators, the generic applicative functor (space invaders) operator is very handy: ``<*>``
131
134
*)
132
135
133
- let sumAllOptions = Some (+) <*> Some 2 <*> Some 10 // val sumAllOptions : int option = Some 12
136
+ let sumAllOptions = Some (+) <*> Some 2 <*> Some 10 // val sumAllOptions : int option = Some 12
134
137
135
- let sumAllElemets = [(+)] <*> [ 10 ; 100 ] <*> [ 1 ; 2 ; 3 ] // int list = [11; 12; 13; 101; 102; 103]
138
+ let sumAllElemets = [(+)] <*> [ 10 ; 100 ] <*> [ 1 ; 2 ; 3 ] // int list = [11; 12; 13; 101; 102; 103]
136
139
137
140
(**
138
141
@@ -154,43 +157,43 @@ from https://github.com/ekmett/lens/wiki/Examples
154
157
First, open F#+ Lens
155
158
*)
156
159
157
- open FSharpPlus.Lens
160
+ open FSharpPlus.Lens
158
161
159
162
(* * Now, you can read from lenses (``_2`` is a lens for the second component of a tuple) *)
160
163
161
- let r1 = ( " hello" , " world" )^._ 2
162
- // val it : string = "world"
164
+ let r1 = ( " hello" , " world" )^._ 2
165
+ // val it : string = "world"
163
166
164
167
(* * and you can write to lenses. *)
165
- let r2 = setl _ 2 42 ( " hello" , " world" )
166
- // val it : string * int = ("hello", 42)
168
+ let r2 = setl _ 2 42 ( " hello" , " world" )
169
+ // val it : string * int = ("hello", 42)
167
170
168
171
(* * Composing lenses for reading (or writing) goes in the order an imperative programmer would expect, and just uses ``(<<)``. *)
169
- let r3 = ( " hello" ,( " world" , " !!!" ))^.(_ 2 << _ 1)
170
- // val it : string = "world"
172
+ let r3 = ( " hello" ,( " world" , " !!!" ))^.(_ 2 << _ 1)
173
+ // val it : string = "world"
171
174
172
- let r4 = setl (_ 2 << _ 1) 42 ( " hello" ,( " world" , " !!!" ))
173
- // val it : string * (int * string) = ("hello", (42, "!!!"))
175
+ let r4 = setl (_ 2 << _ 1) 42 ( " hello" ,( " world" , " !!!" ))
176
+ // val it : string * (int * string) = ("hello", (42, "!!!"))
174
177
175
178
(* * You can make a Getter out of a pure function with ``to'``. *)
176
- let r5 = " hello" ^. to' length
177
- // val it : int = 5
179
+ let r5 = " hello" ^. to' length
180
+ // val it : int = 5
178
181
179
182
(* * You can easily compose a Getter with a Lens just using ``(<<)``. No explicit coercion is necessary. *)
180
- let r6 = ( " hello" ,( " world" , " !!!" ))^. (_ 2 << _ 2 << to' length)
181
- // val it : int = 3
183
+ let r6 = ( " hello" ,( " world" , " !!!" ))^. (_ 2 << _ 2 << to' length)
184
+ // val it : int = 3
182
185
183
186
(* * As we saw above, you can write to lenses and these writes can change the type of the container. ``(.->)`` is an infix alias for ``set``. *)
184
- let r7 = _ 1 .-> " hello" <| ((), " world" )
185
- // val it : string * string = ("hello", "world")
187
+ let r7 = _ 1 .-> " hello" <| ((), " world" )
188
+ // val it : string * string = ("hello", "world")
186
189
187
190
(* * It can be used in conjunction with ``(|>)`` for familiar von Neumann style assignment syntax: *)
188
- let r8 = ((), " world" ) |> _ 1 .-> " hello"
189
- // val it : string * string = ("hello", "world")
191
+ let r8 = ((), " world" ) |> _ 1 .-> " hello"
192
+ // val it : string * string = ("hello", "world")
190
193
191
194
(* * Conversely view, can be used as an prefix alias for ``(^.)``. *)
192
- let r9 = view _ 2 ( 10 , 20 )
193
- // val it : int = 20
195
+ let r9 = view _ 2 ( 10 , 20 )
196
+ // val it : int = 20
194
197
195
198
(**
196
199
0 commit comments