@@ -5,17 +5,18 @@ module option
55
66export_type option
77
8- export some, map
8+ export some/1 , map/2, orElse/2, flatten/1, flatMap/2
99
1010type option 'a = Some 'a | None
1111
1212{- Convenience method to generate a non-empty option.
1313 -}
14+ val some 'a : fn 'a -> option 'a
1415let some a = Some a
1516
1617test "Applying `some` to a literal value yields a non-empty option" =
1718 let o = some 1 in
18- assert.equal Some 1 o
19+ assert.equal ( Some 1) o
1920
2021{- Transform the contents of an option with a function to make a new option.
2122
@@ -42,6 +43,7 @@ test "Applying `some` to a literal value yields a non-empty option" =
4243 map int_to_string Some 2```
4344 ```
4445 -}
46+ val map 'a 'b : fn (fn 'a -> 'b) (option 'a) -> option 'b
4547let map f None = None
4648
4749test "mapping None should produce None" =
@@ -60,4 +62,77 @@ test "mapping double function should double the option" =
6062
6163test "doubling a float option should result yield correct results" =
6264 let double x = x +. x in
63- assert.equal Some 7.0 (map double Some 3.5)
65+ assert.equal Some 7.0 (map double Some 3.5)
66+
67+
68+ {-| Provide a default value, turning an optional value into a normal
69+ value.
70+
71+ ```
72+ orElse 100 (Some 42) == 42
73+ ```
74+ ```
75+ orElse 100 None == 100
76+ ```
77+ -}
78+ val orElse 'a : fn 'a (option 'a) -> 'a
79+ let orElse default op =
80+ match op with
81+ | None -> default
82+ | Some value -> value
83+
84+ test "orElse of None returns default" =
85+ assert.equal (orElse "World" None) "World"
86+
87+ test "orElse of Some returns value" =
88+ assert.equal (orElse "World" (Some "Planet")) "Planet"
89+
90+
91+ {-| Collapse 2 layers of `option` into one.
92+
93+ ```
94+ flatten (Some (Some 42)) == (Some 42)
95+ ```
96+ ```
97+ flatten (Some None) == None
98+ ```
99+ ```
100+ flatten None == None
101+ ```
102+ -}
103+ -- val flatten 'a : fn (option (option 'a)) -> option 'a
104+ let flatten op =
105+ match op with
106+ | None -> None
107+ | Some value -> value
108+
109+ test "flatten of Some Some value" =
110+ assert.equal (flatten (Some (Some :one))) (Some :one)
111+
112+ test "flatten of Some None" =
113+ assert.equal (flatten (Some None)) None
114+
115+ test "flatten of None" =
116+ assert.equal (flatten None) None
117+
118+
119+ {-| Chain together many computations that may fail. We only continue
120+ with the callback if things are going well- if there is a value.
121+
122+ This allows us to chain functions that take a value and return an
123+ optional value.
124+
125+ This function may also be known as "bind", "andThen" or ">>=" in
126+ other languages.
127+ -}
128+ val flatMap 'a 'b : fn (fn 'a -> option 'b) (option 'a) -> option 'b
129+ let flatMap func op =
130+ flatten (map func op)
131+
132+ test "flatMap with None" =
133+ let f x = (Some x + x) in
134+ assert.equal (None) (flatMap f None)
135+
136+ test "flatMap with Some x" =
137+ let f x = (Some x + x) in
138+ assert.equal (Some 2) (flatMap f (Some 1))
0 commit comments