Skip to content

Commit e534fe0

Browse files
authored
Merge pull request #6 from lpil/lp/option
option additions
2 parents d1082bc + af6f204 commit e534fe0

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
_build
2+
rebar3.crashdump
3+
rebar.lock

src/option.alp

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ module option
55

66
export_type option
77

8-
export some, map
8+
export some/1, map/2, orElse/2, flatten/1, flatMap/2
99

1010
type option 'a = Some 'a | None
1111

1212
{- Convenience method to generate a non-empty option.
1313
-}
14+
val some 'a : fn 'a -> option 'a
1415
let some a = Some a
1516

1617
test "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
4547
let map f None = None
4648

4749
test "mapping None should produce None" =
@@ -60,4 +62,77 @@ test "mapping double function should double the option" =
6062

6163
test "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

Comments
 (0)