|
22 | 22 | * along with this program; if not, write to the Free Software
|
23 | 23 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
|
24 | 24 |
|
25 |
| -(** [`Belt.Result`]() |
| 25 | +(** |
| 26 | + Result types are really useful to describe the result of a certain operation |
| 27 | + without relying on exceptions or `option` types. |
26 | 28 |
|
27 |
| - Utilities for result data type. |
| 29 | + This module gives you useful utilities to create and combine `Result` data. |
28 | 30 | *)
|
29 | 31 |
|
30 |
| - |
| 32 | +type ('a,'b) t = Ok of 'a | Error of 'b |
31 | 33 | (**
|
32 |
| - `Belt.Result` is a data type with two variants: `Ok` and `Error`. Each of these variants can |
33 |
| - contain data, and those two pieces of data need not have the same data type. `Belt.Result` is |
34 |
| - useful when you need to not only determine whether some data is valid or not (use `Belt.Option` |
35 |
| - for that), but also keep information about the invalid data. |
| 34 | + The type `Result.t(result, err)` describes a variant of two states: |
| 35 | + `Ok(someResult)` represents a successful operation, whereby |
| 36 | + ``Error(someError)` signals an erronous operation. |
36 | 37 |
|
37 |
| - In the examples, we presume the existence of two variables: |
| 38 | + In this concrete example, we are defining our own `Result` type to reflect an HTTP like |
| 39 | + query operation: |
38 | 40 |
|
39 |
| - ``` |
40 |
| - let good = Ok 42 |
41 |
| - let bad = Error "Invalid data" |
42 |
| - ``` |
43 |
| -*) |
| 41 | + ```res example |
| 42 | + type responseError = NotAvailable | NotFound |
| 43 | + type queryResult = t<string, responseError> |
44 | 44 |
|
45 |
| -type ('a,'b) t = Ok of 'a | Error of 'b |
| 45 | + let failQueryUser = (username: string): queryResult => { |
| 46 | + Error(NotAvailable) |
| 47 | + } |
| 48 | +``` |
| 49 | +*) |
46 | 50 |
|
47 | 51 | val getExn : ('a, 'b) t -> 'a
|
48 | 52 | (**
|
49 |
| - `getExn res` |
| 53 | + `getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception |
50 | 54 |
|
51 |
| - when `res` is `Ok n`, returns `n` |
52 |
| - when `res` is `Error m`, **raise** an exception |
| 55 | + ```res example |
| 56 | + Belt.Result.getExn(Belt.Result.Ok(42)) == 42 |
53 | 57 |
|
54 |
| - ``` |
55 |
| - getExn good = 42;; |
56 |
| - getExn bad;; (* raises exception *) |
| 58 | + Belt.Result.getExn(Belt.Result.Error("Invalid data")) /* raises exception */ |
57 | 59 | ```
|
58 | 60 | *)
|
59 | 61 |
|
60 | 62 | val mapWithDefaultU : ('a, 'c) t -> 'b -> ('a -> 'b [@bs]) -> 'b
|
61 | 63 | val mapWithDefault : ('a, 'c) t -> 'b -> ('a -> 'b) -> 'b
|
62 | 64 | (**
|
63 |
| - `mapWithDefault res default f` |
| 65 | + `mapWithDefault(res, default, f)`: When res is `Ok(n)`, returns `f(n)`, |
| 66 | + otherwise `default`. |
64 | 67 |
|
65 |
| - When `res` is `Ok n`, returns `f n`, otherwise `default`. |
| 68 | + ```res example |
| 69 | + let ok = Belt.Result.Ok(42) |
| 70 | + Belt.Result.mapWithDefault(ok, 0, (x) => x / 2) == 21 |
66 | 71 |
|
67 |
| - ``` |
68 |
| - mapWithDefault good 0 (fun x -> x / 2) = 21 |
69 |
| - mapWithDefault bad 0 (fun x -> x / 2) = 0 |
| 72 | + let error = Belt.Result.Error("Invalid data") |
| 73 | + Belt.Result.mapWithDefault(error, 0, (x) => x / 2) == 0 |
70 | 74 | ```
|
71 | 75 | *)
|
72 | 76 |
|
73 | 77 | val mapU : ('a, 'c) t -> ('a -> 'b [@bs]) -> ('b, 'c) t
|
74 | 78 | val map : ('a, 'c) t -> ('a -> 'b) -> ('b, 'c) t
|
75 | 79 | (**
|
76 |
| - `map res f` |
| 80 | + `map(res, f)`: When res is `Ok(n)`, returns `Ok(f(n))`. Otherwise returns res |
| 81 | + unchanged. Function `f` takes a value of the same type as `n` and returns an |
| 82 | + ordinary value. |
77 | 83 |
|
78 |
| - When `res` is `Ok n`, returns `Ok (f n)`. Otherwise returns `res` unchanged. |
79 |
| - Function `f` takes a value of the same type as `n` and returns an ordinary value. |
| 84 | + ```res example |
| 85 | + let f = (x) => sqrt(Belt.Int.toFloat(x)) |
80 | 86 |
|
81 |
| - ``` |
82 |
| - let f x = sqrt (float_of_int x) |
83 |
| - map (Ok 64) f = Ok 8.0 |
84 |
| - map (Error "Invalid data") f = Error "Invalid data" |
| 87 | + Belt.Result.map(Ok(64), f) == Ok(8.0) |
| 88 | +
|
| 89 | + Belt.Result.map(Error("Invalid data"), f) == Error("Invalid data") |
85 | 90 | ```
|
86 | 91 | *)
|
87 | 92 |
|
88 | 93 | val flatMapU : ('a, 'c) t -> ('a -> ('b, 'c) t [@bs]) -> ('b, 'c) t
|
89 | 94 | val flatMap : ('a, 'c) t -> ('a -> ('b, 'c) t) -> ('b, 'c) t
|
90 | 95 | (**
|
91 |
| - `flatMap res f` |
| 96 | + `flatMap(res, f)`: When res is `Ok(n)`, returns `f(n)`. Otherwise, returns res |
| 97 | + unchanged. Function `f` takes a value of the same type as `n` and returns a |
| 98 | + `Belt.Result`. |
92 | 99 |
|
93 |
| - When `res` is `Ok n`, returns `f n`. Otherwise, returns `res` unchanged. |
94 |
| - Function `f` takes a value of the same type as `n` and returns a `Belt.Result`. |
| 100 | + ```res example |
| 101 | + let recip = (x) => |
| 102 | + if (x !== 0.0) { |
| 103 | + Belt.Result.Ok(1.0 /. x) |
| 104 | + } else { |
| 105 | + Belt.Result.Error("Divide by zero") |
| 106 | + } |
95 | 107 |
|
96 |
| - ``` |
97 |
| - let recip x = |
98 |
| - if x != 0.0 |
99 |
| - then |
100 |
| - Ok (1.0 /. x) |
101 |
| - else |
102 |
| - Error "Divide by zero" |
103 |
| -
|
104 |
| - flatMap (Ok 2.0) recip = Ok 0.5 |
105 |
| - flatMap (Ok 0.0) recip = Error "Divide by zero" |
106 |
| - flatMap (Error "Already bad") recip = Error "Already bad" |
| 108 | + Belt.Result.flatMap(Ok(2.0), recip) == Ok(0.5) |
| 109 | +
|
| 110 | + Belt.Result.flatMap(Ok(0.0), recip) == Error("Divide by zero") |
| 111 | +
|
| 112 | + Belt.Result.flatMap(Error("Already bad"), recip) == Error("Already bad") |
107 | 113 | ```
|
108 | 114 | *)
|
109 | 115 |
|
110 | 116 | val getWithDefault : ('a, 'b) t -> 'a -> 'a
|
111 | 117 | (**
|
112 |
| - `getWithDefault res defaultValue` |
| 118 | + `getWithDefault(res, defaultValue)`: If `res` is `Ok(n)`, returns `n`, |
| 119 | + otherwise `default` |
113 | 120 |
|
114 |
| - if `res` is `Ok n`, returns `n`, otherwise `default` |
| 121 | + ```res example |
| 122 | + Belt.Result.getWithDefault(Ok(42), 0) == 42 |
115 | 123 |
|
116 |
| - ``` |
117 |
| - getWithDefault (Ok 42) 0 = 42 |
118 |
| - getWithDefault (Error "Invalid Data") = 0 |
| 124 | + Belt.Result.getWithDefault(Error("Invalid Data"), 0) == 0 |
119 | 125 | ```
|
120 | 126 | *)
|
121 | 127 |
|
122 | 128 | val isOk : ('a, 'b) t -> bool
|
123 | 129 | (**
|
124 |
| - `isOk res` |
125 |
| -
|
126 |
| - Returns `true` if `res` is of the form `Ok n`, `false` if it is the `Error e` variant. |
| 130 | + `isOk(res)`: Returns `true` if `res` is of the form `Ok(n)`, `false` if it is |
| 131 | + the `Error(e)` variant. |
127 | 132 | *)
|
128 | 133 |
|
129 | 134 | val isError : ('a, 'b) t -> bool
|
130 | 135 | (**
|
131 |
| - `isError res` |
132 |
| -
|
133 |
| - Returns `true` if `res` is of the form `Error e`, `false` if it is the `Ok n` variant. |
| 136 | + `isError(res)`: Returns `true` if `res` is of the form `Error(e)`, `false` if |
| 137 | + it is the `Ok(n)` variant. |
134 | 138 | *)
|
135 | 139 |
|
136 | 140 | val eqU : ('a, 'c) t -> ('b, 'd) t -> ('a -> 'b -> bool [@bs]) -> bool
|
137 | 141 | val eq : ('a, 'c) t -> ('b, 'd) t -> ('a -> 'b -> bool) -> bool
|
138 | 142 | (**
|
139 |
| - `eq res1 res2 f` |
| 143 | + `eq(res1, res2, f)`: Determine if two `Belt.Result` variables are equal with |
| 144 | + respect to an equality function. If `res1` and `res2` are of the form `Ok(n)` |
| 145 | + and `Ok(m)`, return the result of `f(n, m)`. If one of `res1` and `res2` are of |
| 146 | + the form `Error(e)`, return false If both `res1` and `res2` are of the form |
| 147 | + `Error(e)`, return true |
140 | 148 |
|
141 |
| - Determine if two `Belt.Result` variables are equal with respect to an equality function. |
142 |
| - If `res1` and `res2` are of the form `Ok n` and `Ok m`, return the result of `f n m`. |
143 |
| - If one of `res1` and `res2` are of the form `Error e`, return false |
144 |
| - If both `res1` and `res2` are of the form `Error e`, return true |
| 149 | + ```res example |
| 150 | + let good1 = Belt.Result.Ok(42) |
145 | 151 |
|
146 |
| - ``` |
147 |
| - let good1 = Ok 42 |
148 |
| - let good2 = Ok 32 |
149 |
| - let bad1 = Error "invalid" |
150 |
| - let bad2 = Error "really invalid" |
151 |
| -
|
152 |
| - let mod10equal a b = |
153 |
| - a mod 10 == b mod 10 |
154 |
| -
|
155 |
| - eq good1 good2 mod10equal = true |
156 |
| - eq good1 bad1 mod10equal = false |
157 |
| - eq bad2 good2 mod10equal = false |
158 |
| - eq bad1 bad2 mod10equal = true |
| 152 | + let good2 = Belt.Result.Ok(32) |
| 153 | +
|
| 154 | + let bad1 = Belt.Result.Error("invalid") |
| 155 | +
|
| 156 | + let bad2 = Belt.Result.Error("really invalid") |
| 157 | +
|
| 158 | + let mod10equal = (a, b) => mod(a, 10) === mod(b, 10) |
| 159 | +
|
| 160 | + Belt.Result.eq(good1, good2, mod10equal) == true |
| 161 | +
|
| 162 | + Belt.Result.eq(good1, bad1, mod10equal) == false |
| 163 | +
|
| 164 | + Belt.Result.eq(bad2, good2, mod10equal) == false |
| 165 | +
|
| 166 | + Belt.Result.eq(bad1, bad2, mod10equal) == true |
159 | 167 | ```
|
160 | 168 | *)
|
161 | 169 |
|
162 | 170 | val cmpU : ('a, 'c) t -> ('b, 'd) t -> ('a -> 'b -> int [@bs]) -> int
|
163 | 171 | val cmp : ('a, 'c) t -> ('b, 'd) t -> ('a -> 'b -> int) -> int
|
164 | 172 | (**
|
165 |
| - `cmp res1 res2 f` |
| 173 | + `cmp(res1, res2, f)`: Compare two `Belt.Result` variables with respect to a |
| 174 | + comparison function. The comparison function returns -1 if the first variable |
| 175 | + is "less than" the second, 0 if the two variables are equal, and 1 if the first |
| 176 | + is "greater than" the second. |
166 | 177 |
|
167 |
| - Compare two `Belt.Result` variables with respect to a comparison function. |
168 |
| - The comparison function returns -1 if the first variable is "less than" the second, |
169 |
| - 0 if the two variables are equal, and 1 if the first is "greater than" the second. |
| 178 | + If `res1` and `res2` are of the form `Ok(n)` and `Ok(m)`, return the result of |
| 179 | + `f(n, m)`. If `res1` is of the form `Error(e)` and `res2` of the form `Ok(n)`, |
| 180 | + return -1 (nothing is less than something) If `res1` is of the form `Ok(n)` and |
| 181 | + `res2` of the form `Error(e)`, return 1 (something is greater than nothing) If |
| 182 | + both `res1` and `res2` are of the form `Error(e)`, return 0 (equal) |
170 | 183 |
|
171 |
| - If `res1` and `res2` are of the form `Ok n` and `Ok m`, return the result of `f n m`. |
172 |
| - If `res1` is of the form `Error e` and `res2` of the form `Ok n`, return -1 (nothing is less than something) |
173 |
| - If `res1` is of the form `Ok n` and `res2` of the form `Error e`, return 1 (something is greater than nothing) |
174 |
| - If both `res1` and `res2` are of the form `Error e`, return 0 (equal) |
| 184 | + ```res example |
| 185 | + let good1 = Belt.Result.Ok(59) |
175 | 186 |
|
176 |
| - ``` |
177 |
| - let good1 = Ok 59 |
178 |
| - let good2 = Ok 37 |
179 |
| - let bad1 = Error "invalid" |
180 |
| - let bad2 = Error "really invalid" |
181 |
| -
|
182 |
| - let mod10cmp a b = |
183 |
| - Pervasives.compare (a mod 10) (b mod 10) |
184 |
| -
|
185 |
| - cmp (Ok 39) (Ok 57) mod10cmp = 1 |
186 |
| - cmp (Ok 57) (Ok 39) mod10cmp = -1 |
187 |
| - cmp (Ok 39) (Error "y") mod10cmp = 1 |
188 |
| - cmp (Error "x") (Ok 57) mod10cmp = -1 |
189 |
| - cmp (Error "x") (Error "y") mod10cmp = 0 |
| 187 | + let good2 = Belt.Result.Ok(37) |
| 188 | +
|
| 189 | + let bad1 = Belt.Result.Error("invalid") |
| 190 | +
|
| 191 | + let bad2 = Belt.Result.Error("really invalid") |
| 192 | +
|
| 193 | + let mod10cmp = (a, b) => Pervasives.compare(mod(a, 10), mod(b, 10)) |
| 194 | +
|
| 195 | + Belt.Result.cmp(Ok(39), Ok(57), mod10cmp) == 1 |
| 196 | +
|
| 197 | + Belt.Result.cmp(Ok(57), Ok(39), mod10cmp) == (-1) |
| 198 | +
|
| 199 | + Belt.Result.cmp(Ok(39), Error("y"), mod10cmp) == 1 |
| 200 | +
|
| 201 | + Belt.Result.cmp(Error("x"), Ok(57), mod10cmp) == (-1) |
| 202 | +
|
| 203 | + Belt.Result.cmp(Error("x"), Error("y"), mod10cmp) == 0 |
190 | 204 | ```
|
191 | 205 | *)
|
0 commit comments