33// it to define helpers that you do not want to show in the documentation.
44
55#r @" ../../src/FSharpPlus/bin/Release/netstandard2.0/FSharpPlus.dll"
6- #nowarn " 0058" // We need to cheat a bit with indentation here.
76
87(**
98Introducing FSharpPlus
@@ -20,12 +19,11 @@ Introducing FSharpPlus
2019#r @"nuget: FSharpPlus"
2120```
2221*)
23- open FSharpPlus
24-
25- (**
26- Ignore warnings about F# metadata if any.
2722
23+ (* ** hide ***)
24+ module [<AutoOpen>] E1 =
2825
26+ (**
2927Now we'll start with a quick overview of the features presented in F#+.
3028
3129### Generic functions
@@ -36,33 +34,35 @@ here's an example with <code>map</code> ([fmap](https://wiki.haskell.org/Functor
3634
3735*)
3836
39- map string [| 2 ; 3 ; 4 ; 5 |]
40- // val it : string [] = [|"2"; "3"; "4"; "5"|]
37+ open FSharpPlus
4138
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"|]
4441
45- open FSharpPlus.Data
42+ map ((+) 9 ) ( Some 3 )
43+ // val it : int option = Some 12
4644
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"];}
4949
5050(**
5151They're also available for your own types as long as they contain the appropriated method with the expected signature
5252*)
5353
5454
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)
6666
6767(**
6868Generic 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
7272Here you have a ready-to-use generic bind operator: `` >>= ``
7373*)
7474
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']
7777
7878
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)
8181
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
8484
8585(**
8686You have also the Kleisli composition (fish) operator: `` >=> ``
8787
8888Which is becoming popular in F# after the [ Railway Oriented Programming] ( https://www.google.ch/#q=railway+oriented+programming ) tutorial series
8989*)
9090
91- let parseAndDivide100By = tryParseInt >=> tryDivide 100
91+ let parseAndDivide100By = tryParseInt >=> tryDivide 100
9292
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
9696
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" ]
9999
100100(**
101101But 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:
102102*)
103103
104104(* ** hide ***)
105- module E2 =
105+ open FSharpPlus
106+
107+ (* ** hide ***)
108+ module E2 =
106109
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)
111114
112115
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)
116119
117120(**
118121The test code remains unchanged, but we get a more interesting functionality
119122*)
120123
121- let parseAndDivide100By = tryParseInt >=> tryDivide 100
124+ let parseAndDivide100By = tryParseInt >=> tryDivide 100
122125
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"
126129
127130
128131(**
129132
130133Also when working with combinators, the generic applicative functor (space invaders) operator is very handy: `` <*> ``
131134*)
132135
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
134137
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]
136139
137140(**
138141
@@ -154,43 +157,43 @@ from https://github.com/ekmett/lens/wiki/Examples
154157First, open F#+ Lens
155158*)
156159
157- open FSharpPlus.Lens
160+ open FSharpPlus.Lens
158161
159162(* * Now, you can read from lenses (``_2`` is a lens for the second component of a tuple) *)
160163
161- let r1 = ( " hello" , " world" )^._ 2
162- // val it : string = "world"
164+ let r1 = ( " hello" , " world" )^._ 2
165+ // val it : string = "world"
163166
164167(* * 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)
167170
168171(* * 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"
171174
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, "!!!"))
174177
175178(* * 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
178181
179182(* * 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
182185
183186(* * 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")
186189
187190(* * 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")
190193
191194(* * 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
194197
195198(**
196199
0 commit comments