silo:std.result

Source src/silo:std.result

1##! Result combinator methods — the `Res` trait.
2##!
3##! Gives `Result` values the familiar `.map`, `.map-err`, `.and-then`,
4##! `.ok`, `.err` surface.
5
6:use
7  :open core Bool Never Option None Some Result Ok Err Str
8  :open traits Eq
9  :open effects.panic panic
10:end
11
12# si[impl stdlib.result.trait+1]
13## Combinator surface on `(Result val err)`. `.map` / `.map-err` transform one side
14## while preserving the other; `.and-then` / `.or-else` chain into further fallible
15## computations. `.ok` / `.err` project either side to an `Option`.
16:trait(pub) Res
17  ## True iff the Result is `Ok`.
18  .is-ok ( (Result val err) -> Bool )
19  ## True iff the Result is `Err`.
20  .is-err ( (Result val err) -> Bool )
21  ## Apply a function to the `Ok` value; the `Err` branch is unchanged.
22  .map ( [a -> b] (Result a err) -> (Result b err) )
23  ## Apply a function to the `Err` value; the `Ok` branch is unchanged.
24  .map-err ( [e1 -> e2] (Result val e1) -> (Result val e2) )
25  ## Chain into another Result-producing computation on the `Ok` side (monadic bind).
26  .and-then ( [a -> (Result b err)] (Result a err) -> (Result b err) )
27  ## Attempt to recover from `Err` by invoking a fallback; `Ok` passes through.
28  .or-else ( [e1 -> (Result val e2)] (Result val e1) -> (Result val e2) )
29  ## Return the `Ok` value, panicking if `Err`.
30  .unwrap ( (Result val err) -> val ) +Panic
31  ## Return the `Err` value, panicking if `Ok`.
32  .unwrap-err ( (Result val err) -> err ) +Panic
33  ## Return the `Ok` value, panicking with the supplied message if `Err`.
34  .expect ( (Result a e) Str -> a ) +Panic
35  ## Return the `Err` value, panicking with the supplied message if `Ok`.
36  .expect-err ( (Result a e) Str -> e ) +Panic
37  ## Return the `Ok` value, or a fixed fallback if `Err`.
38  .unwrap-or ( val (Result val err) -> val )
39  ## Return the `Ok` value, or invoke a function on the error to produce one if `Err`.
40  .unwrap-or-else ( [err -> val] (Result val err) -> val )
41  ## Extract the `Ok` value from a `(Result a Never)` — the `Err` arm is uninhabited.
42  .into-ok ( (Result a Never) -> a )
43  ## Extract the `Err` value from a `(Result Never e)` — the `Ok` arm is uninhabited.
44  .into-err ( (Result Never e) -> e )
45  ## Project to `Some val` when `Ok`, `None` when `Err`.
46  .ok ( (Result val err) -> (Option val) )
47  ## Project to `Some err` when `Err`, `None` when `Ok`.
48  .err ( (Result val err) -> (Option err) )
49  ## Collapse `(Result (Result val err) err)` into `(Result val err)` by one layer.
50  .flatten ( (Result (Result val err) err) -> (Result val err) )
51  .map-or ( (Result a e) b [a -> b] -> b )
52  .map-or-else ( (Result a e) [e -> b] [a -> b] -> b )
53  .and ( (Result a e) (Result b e) -> (Result b e) )
54  .or ( (Result a e) (Result a f) -> (Result a f) )
55  .is-ok-and ( (Result a e) [a -> Bool] -> Bool )
56  .is-err-and ( (Result a e) [e -> Bool] -> Bool )
57  .transpose ( (Result (Option a) e) -> (Option (Result a e)) )
58  ## Call a quotation on the `Ok` value for side effects, returning the Result unchanged.
59  .inspect ( (Result a e) [a -> ] -> (Result a e) ) +eff
60  ## Call a quotation on the `Err` value for side effects, returning the Result unchanged.
61  .inspect-err ( (Result a e) [e -> ] -> (Result a e) ) +eff
62  ## True iff the Result is `Ok` and the inner value equals the supplied argument.
63  .contains ( (Result a e) a -> Bool ) { (Eq a a) }
64  ## True iff the Result is `Err` and the error value equals the supplied argument.
65  .contains-err ( (Result a e) e -> Bool ) { (Eq e e) }
66:end
67
68:impl Res (Result val err)
69  .is-ok ( (Result val err) -> Bool )
70    :match | Ok _ => true | Err _ => false :end ;
71
72  .is-err ( (Result val err) -> Bool )
73    :match | Ok _ => false | Err _ => true :end ;
74
75  .map ( [a -> b] (Result a err) -> (Result b err) )
76    :match
77      | Ok x  => x swap .call Ok
78      | Err e => drop e Err
79    :end ;
80
81  .map-err ( [e1 -> e2] (Result val e1) -> (Result val e2) )
82    :match
83      | Ok x  => drop x Ok
84      | Err e => e swap .call Err
85    :end ;
86
87  .and-then ( [a -> (Result b err)] (Result a err) -> (Result b err) )
88    :match
89      | Ok x  => x swap .call
90      | Err e => drop e Err
91    :end ;
92
93  .or-else ( [e1 -> (Result val e2)] (Result val e1) -> (Result val e2) )
94    :match
95      | Ok x  => drop x Ok
96      | Err e => e swap .call
97    :end ;
98
99  # si[impl stdlib.result.unwrap+1]
100  .unwrap ( (Result val err) -> val ) +Panic
101    :match
102      | Ok x  => x
103      | Err _ => "unwrap called on Err" panic
104    :end ;
105
106  # si[impl stdlib.result.unwrap-err+1]
107  .unwrap-err ( (Result val err) -> err ) +Panic
108    :match
109      | Ok _  => "unwrap-err called on Ok" panic
110      | Err e => e
111    :end ;
112
113  # si[impl stdlib.result.expect]
114  .expect ( (Result a e) Str -> a ) +Panic
115    pop-> msg
116    :match
117      | Ok x  => x
118      | Err _ => msg panic
119    :end ;
120
121  # si[impl stdlib.result.expect-err]
122  .expect-err ( (Result a e) Str -> e ) +Panic
123    pop-> msg
124    :match
125      | Ok _  => msg panic
126      | Err e => e
127    :end ;
128
129  .unwrap-or ( val (Result val err) -> val )
130    :match
131      | Ok x  => drop x
132      | Err _ =>
133    :end ;
134
135  .unwrap-or-else ( [err -> val] (Result val err) -> val )
136    :match
137      | Ok x  => drop x
138      | Err e => e swap .call
139    :end ;
140
141  # si[impl stdlib.result.into-ok]
142  .into-ok ( (Result a Never) -> a )
143    :match | Ok x => x :end ;
144
145  # si[impl stdlib.result.into-err]
146  .into-err ( (Result Never e) -> e )
147    :match | Err e => e :end ;
148
149  .ok ( (Result val err) -> (Option val) )
150    :match
151      | Ok x  => x Some
152      | Err _ => None
153    :end ;
154
155  .err ( (Result val err) -> (Option err) )
156    :match
157      | Ok _  => None
158      | Err e => e Some
159    :end ;
160
161  .flatten ( (Result (Result val err) err) -> (Result val err) )
162    :match
163      | Ok inner => inner
164      | Err e    => e Err
165    :end ;
166
167  .map-or ( (Result a e) b [a -> b] -> b )
168    pop-> f pop-> default
169    :match
170      | Ok x  => x f .call
171      | Err _ => default
172    :end ;
173
174  .map-or-else ( (Result a e) [e -> b] [a -> b] -> b )
175    pop-> f pop-> default-fn
176    :match
177      | Ok x  => x f .call
178      | Err e => e default-fn .call
179    :end ;
180
181  .and ( (Result a e) (Result b e) -> (Result b e) )
182    swap :match
183      | Ok _  =>
184      | Err e => drop e Err
185    :end ;
186
187  .or ( (Result a e) (Result a f) -> (Result a f) )
188    swap :match
189      | Ok x  => drop x Ok
190      | Err _ =>
191    :end ;
192
193  .is-ok-and ( (Result a e) [a -> Bool] -> Bool )
194    pop-> pred
195    :match
196      | Ok x  => x pred .call
197      | Err _ => false
198    :end ;
199
200  .is-err-and ( (Result a e) [e -> Bool] -> Bool )
201    pop-> pred
202    :match
203      | Ok _  => false
204      | Err e => e pred .call
205    :end ;
206
207  .transpose ( (Result (Option a) e) -> (Option (Result a e)) )
208    :match
209      | Ok inner => inner :match
210          | None   => None
211          | Some x => x Ok Some
212        :end
213      | Err e    => e Err Some
214    :end ;
215
216  # si[impl stdlib.result.inspect]
217  .inspect ( (Result a e) [a -> ] -> (Result a e) ) +eff
218    pop-> f
219    :match
220      | Ok x  => x f .call x Ok
221      | Err e => e Err
222    :end ;
223
224  # si[impl stdlib.result.inspect-err]
225  .inspect-err ( (Result a e) [e -> ] -> (Result a e) ) +eff
226    pop-> f
227    :match
228      | Ok x  => x Ok
229      | Err e => e f .call e Err
230    :end ;
231
232  # si[impl stdlib.result.contains]
233  .contains ( (Result a e) a -> Bool ) { (Eq a a) }
234    pop-> val
235    :match
236      | Ok x  => x val .=
237      | Err _ => false
238    :end ;
239
240  # si[impl stdlib.result.contains-err]
241  .contains-err ( (Result a e) e -> Bool ) { (Eq e e) }
242    pop-> val
243    :match
244      | Ok _  => false
245      | Err e => e val .=
246    :end ;
247:end