fp_library/types/option.rs
1//! Implementations for [`Option`].
2//!
3//! This module provides implementations of functional programming traits for the standard library [`Option`] type.
4
5use crate::{
6 Apply,
7 brands::OptionBrand,
8 classes::{
9 applicative::Applicative, apply_first::ApplyFirst, apply_second::ApplySecond,
10 clonable_fn::ClonableFn, compactable::Compactable, filterable::Filterable,
11 foldable::Foldable, functor::Functor, lift::Lift, monoid::Monoid,
12 par_foldable::ParFoldable, pointed::Pointed, semiapplicative::Semiapplicative,
13 semimonad::Semimonad, send_clonable_fn::SendClonableFn, traversable::Traversable,
14 witherable::Witherable,
15 },
16 impl_kind,
17 kinds::*,
18 types::Pair,
19};
20
21impl_kind! {
22 for OptionBrand {
23 type Of<'a, A: 'a>: 'a = Option<A>;
24 }
25}
26
27impl Functor for OptionBrand {
28 /// Maps a function over the value in the option.
29 ///
30 /// This method applies a function to the value inside the option, producing a new option with the transformed value. If the option is `None`, it returns `None`.
31 ///
32 /// ### Type Signature
33 ///
34 /// `forall a b. Functor Option => (a -> b, Option a) -> Option b`
35 ///
36 /// ### Parameters
37 ///
38 /// * `f`: The function to apply to the value.
39 /// * `fa`: The option to map over.
40 ///
41 /// ### Returns
42 ///
43 /// A new option containing the result of applying the function, or `None`.
44 ///
45 /// ### Examples
46 ///
47 /// ```
48 /// use fp_library::classes::functor::Functor;
49 /// use fp_library::brands::OptionBrand;
50 ///
51 /// let x = Some(5);
52 /// let y = OptionBrand::map(|i| i * 2, x);
53 /// assert_eq!(y, Some(10));
54 ///
55 /// // Using the free function
56 /// use fp_library::classes::functor::map;
57 /// assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x * 2, Some(5)), Some(10));
58 /// assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x * 2, None), None);
59 /// ```
60 fn map<'a, F, A: 'a, B: 'a>(
61 f: F,
62 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
63 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
64 where
65 F: Fn(A) -> B + 'a,
66 {
67 fa.map(f)
68 }
69}
70
71impl Lift for OptionBrand {
72 /// Lifts a binary function into the option context.
73 ///
74 /// This method lifts a binary function to operate on values within the option context.
75 ///
76 /// ### Type Signature
77 ///
78 /// `forall a b c. Lift Option => ((a, b) -> c, Option a, Option b) -> Option c`
79 ///
80 /// ### Parameters
81 ///
82 /// * `f`: The binary function to apply.
83 /// * `fa`: The first option.
84 /// * `fb`: The second option.
85 ///
86 /// ### Returns
87 ///
88 /// `Some(f(a, b))` if both options are `Some`, otherwise `None`.
89 ///
90 /// ### Examples
91 ///
92 /// ```
93 /// use fp_library::classes::lift::Lift;
94 /// use fp_library::brands::OptionBrand;
95 ///
96 /// let x = Some(1);
97 /// let y = Some(2);
98 /// let z = OptionBrand::lift2(|a, b| a + b, x, y);
99 /// assert_eq!(z, Some(3));
100 ///
101 /// // Using the free function
102 /// use fp_library::classes::lift::lift2;
103 /// assert_eq!(lift2::<OptionBrand, _, _, _, _>(|x: i32, y: i32| x + y, Some(1), Some(2)), Some(3));
104 /// assert_eq!(lift2::<OptionBrand, _, _, _, _>(|x: i32, y: i32| x + y, Some(1), None), None);
105 /// ```
106 fn lift2<'a, F, A, B, C>(
107 f: F,
108 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
109 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
110 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
111 where
112 F: Fn(A, B) -> C + 'a,
113 A: 'a,
114 B: 'a,
115 C: 'a,
116 {
117 fa.zip(fb).map(|(a, b)| f(a, b))
118 }
119}
120
121impl Pointed for OptionBrand {
122 /// Wraps a value in an option.
123 ///
124 /// This method wraps a value in an option context.
125 ///
126 /// ### Type Signature
127 ///
128 /// `forall a. Pointed Option => a -> Option a`
129 ///
130 /// ### Parameters
131 ///
132 /// * `a`: The value to wrap.
133 ///
134 /// ### Returns
135 ///
136 /// `Some(a)`.
137 ///
138 /// ### Examples
139 ///
140 /// ```
141 /// use fp_library::classes::pointed::Pointed;
142 /// use fp_library::brands::OptionBrand;
143 ///
144 /// let x = OptionBrand::pure(5);
145 /// assert_eq!(x, Some(5));
146 ///
147 /// // Using the free function
148 /// use fp_library::classes::pointed::pure;
149 /// assert_eq!(pure::<OptionBrand, _>(5), Some(5));
150 /// ```
151 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
152 Some(a)
153 }
154}
155
156impl ApplyFirst for OptionBrand {}
157impl ApplySecond for OptionBrand {}
158
159impl Semiapplicative for OptionBrand {
160 /// Applies a wrapped function to a wrapped value.
161 ///
162 /// This method applies a function wrapped in an option to a value wrapped in an option.
163 ///
164 /// ### Type Signature
165 ///
166 /// `forall a b. Semiapplicative Option => (Option (a -> b), Option a) -> Option b`
167 ///
168 /// ### Parameters
169 ///
170 /// * `ff`: The option containing the function.
171 /// * `fa`: The option containing the value.
172 ///
173 /// ### Returns
174 ///
175 /// `Some(f(a))` if both are `Some`, otherwise `None`.
176 ///
177 /// ### Examples
178 ///
179 /// ```
180 /// use fp_library::classes::semiapplicative::Semiapplicative;
181 /// use fp_library::classes::clonable_fn::ClonableFn;
182 /// use fp_library::brands::{OptionBrand};
183 /// use fp_library::brands::RcFnBrand;
184 /// use std::rc::Rc;
185 ///
186 /// let f = Some(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
187 /// let x = Some(5);
188 /// let y = OptionBrand::apply::<RcFnBrand, i32, i32>(f, x);
189 /// assert_eq!(y, Some(10));
190 ///
191 /// // Using the free function
192 /// use fp_library::classes::semiapplicative::apply;
193 /// let f = Some(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
194 /// assert_eq!(apply::<RcFnBrand, OptionBrand, _, _>(f, Some(5)), Some(10));
195 /// ```
196 fn apply<'a, FnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
197 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as ClonableFn>::Of<'a, A, B>>),
198 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
199 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
200 match (ff, fa) {
201 (Some(f), Some(a)) => Some(f(a)),
202 _ => None,
203 }
204 }
205}
206
207impl Semimonad for OptionBrand {
208 /// Chains option computations.
209 ///
210 /// This method chains two option computations, where the second computation depends on the result of the first.
211 ///
212 /// ### Type Signature
213 ///
214 /// `forall a b. Semimonad Option => (Option a, a -> Option b) -> Option b`
215 ///
216 /// ### Parameters
217 ///
218 /// * `ma`: The first option.
219 /// * `f`: The function to apply to the value inside the option.
220 ///
221 /// ### Returns
222 ///
223 /// The result of applying `f` to the value if `ma` is `Some`, otherwise `None`.
224 ///
225 /// ### Examples
226 ///
227 /// ```
228 /// use fp_library::classes::semimonad::Semimonad;
229 /// use fp_library::brands::OptionBrand;
230 ///
231 /// let x = Some(5);
232 /// let y = OptionBrand::bind(x, |i| Some(i * 2));
233 /// assert_eq!(y, Some(10));
234 ///
235 /// // Using the free function
236 /// use fp_library::classes::semimonad::bind;
237 /// assert_eq!(bind::<OptionBrand, _, _, _>(Some(5), |x| Some(x * 2)), Some(10));
238 /// assert_eq!(bind::<OptionBrand, _, _, _>(None, |x: i32| Some(x * 2)), None);
239 /// ```
240 fn bind<'a, F, A: 'a, B: 'a>(
241 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
242 f: F,
243 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
244 where
245 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
246 {
247 ma.and_then(f)
248 }
249}
250
251impl Foldable for OptionBrand {
252 /// Folds the option from the right.
253 ///
254 /// This method performs a right-associative fold of the option. If the option is `Some(a)`, it applies the function to `a` and the initial value. If `None`, it returns the initial value.
255 ///
256 /// ### Type Signature
257 ///
258 /// `forall a b. Foldable Option => ((a, b) -> b, b, Option a) -> b`
259 ///
260 /// ### Parameters
261 ///
262 /// * `func`: The folding function.
263 /// * `initial`: The initial value.
264 /// * `fa`: The option to fold.
265 ///
266 /// ### Returns
267 ///
268 /// `func(a, initial)` if `fa` is `Some(a)`, otherwise `initial`.
269 ///
270 /// ### Examples
271 ///
272 /// ```
273 /// use fp_library::classes::foldable::Foldable;
274 /// use fp_library::brands::OptionBrand;
275 /// use fp_library::brands::RcFnBrand;
276 ///
277 /// let x = Some(5);
278 /// let y = OptionBrand::fold_right::<RcFnBrand, _, _, _>(|a, b| a + b, 10, x);
279 /// assert_eq!(y, 15);
280 ///
281 /// // Using the free function
282 /// use fp_library::classes::foldable::fold_right;
283 /// assert_eq!(fold_right::<RcFnBrand, OptionBrand, _, _, _>(|x: i32, acc| x + acc, 0, Some(5)), 5);
284 /// assert_eq!(fold_right::<RcFnBrand, OptionBrand, _, _, _>(|x: i32, acc| x + acc, 0, None), 0);
285 /// ```
286 fn fold_right<'a, FnBrand, Func, A: 'a, B: 'a>(
287 func: Func,
288 initial: B,
289 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
290 ) -> B
291 where
292 Func: Fn(A, B) -> B + 'a,
293 FnBrand: ClonableFn + 'a,
294 {
295 match fa {
296 Some(a) => func(a, initial),
297 None => initial,
298 }
299 }
300
301 /// Folds the option from the left.
302 ///
303 /// This method performs a left-associative fold of the option. If the option is `Some(a)`, it applies the function to the initial value and `a`. If `None`, it returns the initial value.
304 ///
305 /// ### Type Signature
306 ///
307 /// `forall a b. Foldable Option => ((b, a) -> b, b, Option a) -> b`
308 ///
309 /// ### Parameters
310 ///
311 /// * `func`: The function to apply to the accumulator and each element.
312 /// * `initial`: The initial value of the accumulator.
313 /// * `fa`: The option to fold.
314 ///
315 /// ### Returns
316 ///
317 /// `f(initial, a)` if `fa` is `Some(a)`, otherwise `initial`.
318 ///
319 /// ### Examples
320 ///
321 /// ```
322 /// use fp_library::classes::foldable::Foldable;
323 /// use fp_library::brands::OptionBrand;
324 /// use fp_library::brands::RcFnBrand;
325 ///
326 /// let x = Some(5);
327 /// let y = OptionBrand::fold_left::<RcFnBrand, _, _, _>(|b, a| b + a, 10, x);
328 /// assert_eq!(y, 15);
329 ///
330 /// // Using the free function
331 /// use fp_library::classes::foldable::fold_left;
332 /// assert_eq!(fold_left::<RcFnBrand, OptionBrand, _, _, _>(|acc, x: i32| acc + x, 0, Some(5)), 5);
333 /// ```
334 fn fold_left<'a, FnBrand, Func, A: 'a, B: 'a>(
335 func: Func,
336 initial: B,
337 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
338 ) -> B
339 where
340 Func: Fn(B, A) -> B + 'a,
341 FnBrand: ClonableFn + 'a,
342 {
343 match fa {
344 Some(a) => func(initial, a),
345 None => initial,
346 }
347 }
348
349 /// Maps the value to a monoid and returns it, or returns empty.
350 ///
351 /// This method maps the element of the option to a monoid. If the option is `None`, it returns the monoid's identity element.
352 ///
353 /// ### Type Signature
354 ///
355 /// `forall a m. (Foldable Option, Monoid m) => ((a) -> m, Option a) -> m`
356 ///
357 /// ### Parameters
358 ///
359 /// * `func`: The mapping function.
360 /// * `fa`: The option to fold.
361 ///
362 /// ### Returns
363 ///
364 /// `func(a)` if `fa` is `Some(a)`, otherwise `M::empty()`.
365 ///
366 /// ### Examples
367 ///
368 /// ```
369 /// use fp_library::classes::foldable::Foldable;
370 /// use fp_library::brands::OptionBrand;
371 /// use fp_library::types::string; // Import to bring Monoid impl for String into scope
372 /// use fp_library::brands::RcFnBrand;
373 ///
374 /// let x = Some(5);
375 /// let y = OptionBrand::fold_map::<RcFnBrand, _, _, _>(|a: i32| a.to_string(), x);
376 /// assert_eq!(y, "5".to_string());
377 ///
378 /// // Using the free function
379 /// use fp_library::classes::foldable::fold_map;
380 /// assert_eq!(fold_map::<RcFnBrand, OptionBrand, _, _, _>(|x: i32| x.to_string(), Some(5)), "5".to_string());
381 /// ```
382 fn fold_map<'a, FnBrand, Func, A: 'a, M>(
383 func: Func,
384 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
385 ) -> M
386 where
387 M: Monoid + 'a,
388 Func: Fn(A) -> M + 'a,
389 FnBrand: ClonableFn + 'a,
390 {
391 match fa {
392 Some(a) => func(a),
393 None => M::empty(),
394 }
395 }
396}
397
398impl Traversable for OptionBrand {
399 /// Traverses the option with an applicative function.
400 ///
401 /// This method maps the element of the option to a computation, evaluates it, and wraps the result in the applicative context. If `None`, it returns `pure(None)`.
402 ///
403 /// ### Type Signature
404 ///
405 /// `forall a b f. (Traversable Option, Applicative f) => (a -> f b, Option a) -> f (Option b)`
406 ///
407 /// ### Parameters
408 ///
409 /// * `func`: The function to apply to each element, returning a value in an applicative context.
410 /// * `ta`: The option to traverse.
411 ///
412 /// ### Returns
413 ///
414 /// The option wrapped in the applicative context.
415 ///
416 /// ### Examples
417 ///
418 /// ```
419 /// use fp_library::classes::traversable::Traversable;
420 /// use fp_library::brands::OptionBrand;
421 ///
422 /// let x = Some(5);
423 /// let y = OptionBrand::traverse::<OptionBrand, _, _, _>(|a| Some(a * 2), x);
424 /// assert_eq!(y, Some(Some(10)));
425 ///
426 /// // Using the free function
427 /// use fp_library::classes::traversable::traverse;
428 /// assert_eq!(traverse::<OptionBrand, OptionBrand, _, _, _>(|x| Some(x * 2), Some(5)), Some(Some(10)));
429 /// ```
430 fn traverse<'a, F: Applicative, Func, A: 'a + Clone, B: 'a + Clone>(
431 func: Func,
432 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
433 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
434 where
435 Func: Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
436 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone,
437 {
438 match ta {
439 Some(a) => F::map(|b| Some(b), func(a)),
440 None => F::pure(None),
441 }
442 }
443 /// Sequences an option of applicative.
444 ///
445 /// This method evaluates the computation inside the option and wraps the result in the applicative context. If `None`, it returns `pure(None)`.
446 ///
447 /// ### Type Signature
448 ///
449 /// `forall a f. (Traversable Option, Applicative f) => (Option (f a)) -> f (Option a)`
450 ///
451 /// ### Parameters
452 ///
453 /// * `ta`: The option containing the applicative value.
454 ///
455 /// # Returns
456 ///
457 /// The option wrapped in the applicative context.
458 ///
459 /// ### Examples
460 ///
461 /// ```
462 /// use fp_library::classes::traversable::Traversable;
463 /// use fp_library::brands::OptionBrand;
464 ///
465 /// let x = Some(Some(5));
466 /// let y = OptionBrand::sequence::<OptionBrand, _>(x);
467 /// assert_eq!(y, Some(Some(5)));
468 ///
469 /// // Using the free function
470 /// use fp_library::classes::traversable::sequence;
471 /// assert_eq!(sequence::<OptionBrand, OptionBrand, _>(Some(Some(5))), Some(Some(5)));
472 /// ```
473 fn sequence<'a, F: Applicative, A: 'a + Clone>(
474 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
475 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
476 where
477 Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
478 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
479 {
480 match ta {
481 Some(fa) => F::map(|a| Some(a), fa),
482 None => F::pure(None),
483 }
484 }
485}
486
487impl<FnBrand: SendClonableFn> ParFoldable<FnBrand> for OptionBrand {
488 /// Maps the value to a monoid and returns it, or returns empty, in parallel.
489 ///
490 /// This method maps the element of the option to a monoid. Since `Option` contains at most one element, no actual parallelism occurs, but the interface is satisfied.
491 ///
492 /// ### Type Signature
493 ///
494 /// `forall a m. (ParFoldable Option, Monoid m, Send m, Sync m) => (f a m, Option a) -> m`
495 ///
496 /// ### Parameters
497 ///
498 /// * `func`: The mapping function.
499 /// * `fa`: The option to fold.
500 ///
501 /// ### Returns
502 ///
503 /// The combined monoid value.
504 ///
505 /// ### Examples
506 ///
507 /// ```
508 /// use fp_library::classes::par_foldable::ParFoldable;
509 /// use fp_library::brands::{OptionBrand, ArcFnBrand};
510 /// use fp_library::classes::send_clonable_fn::SendClonableFn;
511 /// use fp_library::classes::send_clonable_fn::new_send;
512 ///
513 /// let x = Some(1);
514 /// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
515 /// let y = <OptionBrand as ParFoldable<ArcFnBrand>>::par_fold_map(f, x);
516 /// assert_eq!(y, "1".to_string());
517 ///
518 /// // Using the free function
519 /// use fp_library::classes::par_foldable::par_fold_map;
520 /// let x = Some(1);
521 /// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
522 /// assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "1".to_string());
523 /// ```
524 fn par_fold_map<'a, A, M>(
525 func: <FnBrand as SendClonableFn>::SendOf<'a, A, M>,
526 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
527 ) -> M
528 where
529 A: 'a + Clone + Send + Sync,
530 M: Monoid + Send + Sync + 'a,
531 {
532 match fa {
533 Some(a) => func(a),
534 None => M::empty(),
535 }
536 }
537}
538
539impl Compactable for OptionBrand {
540 /// Compacts a nested option.
541 ///
542 /// This method flattens a nested option.
543 ///
544 /// ### Type Signature
545 ///
546 /// `forall a. Compactable Option => Option (Option a) -> Option a`
547 ///
548 /// ### Parameters
549 ///
550 /// * `fa`: The nested option.
551 ///
552 /// ### Returns
553 ///
554 /// The flattened option.
555 ///
556 /// ### Examples
557 ///
558 /// ```
559 /// use fp_library::classes::compactable::Compactable;
560 /// use fp_library::brands::OptionBrand;
561 ///
562 /// let x = Some(Some(5));
563 /// let y = OptionBrand::compact(x);
564 /// assert_eq!(y, Some(5));
565 /// ```
566 fn compact<'a, A: 'a>(
567 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
568 'a,
569 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
570 >)
571 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
572 fa.flatten()
573 }
574
575 /// Separates an option of result.
576 ///
577 /// This method separates an option of result into a pair of options.
578 ///
579 /// ### Type Signature
580 ///
581 /// `forall e o. Compactable Option => Option (Result o e) -> (Option o, Option e)`
582 ///
583 /// ### Parameters
584 ///
585 /// * `fa`: The option of result.
586 ///
587 /// ### Returns
588 ///
589 /// A pair of options.
590 ///
591 /// ### Examples
592 ///
593 /// ```
594 /// use fp_library::classes::compactable::Compactable;
595 /// use fp_library::brands::OptionBrand;
596 /// use fp_library::types::Pair;
597 ///
598 /// let x: Option<Result<i32, &str>> = Some(Ok(5));
599 /// let Pair(oks, errs) = OptionBrand::separate(x);
600 /// assert_eq!(oks, Some(5));
601 /// assert_eq!(errs, None);
602 /// ```
603 fn separate<'a, E: 'a, O: 'a>(
604 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
605 ) -> Pair<
606 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
607 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
608 > {
609 match fa {
610 Some(Ok(o)) => Pair(Some(o), None),
611 Some(Err(e)) => Pair(None, Some(e)),
612 None => Pair(None, None),
613 }
614 }
615}
616
617impl Filterable for OptionBrand {
618 /// Partitions an option based on a function that returns a result.
619 ///
620 /// This method partitions an option based on a function that returns a result.
621 ///
622 /// ### Type Signature
623 ///
624 /// `forall a e o. Filterable Option => (a -> Result o e) -> Option a -> (Option o, Option e)`
625 ///
626 /// ### Parameters
627 ///
628 /// * `func`: The function to apply.
629 /// * `fa`: The option to partition.
630 ///
631 /// ### Returns
632 ///
633 /// A pair of options.
634 ///
635 /// ### Examples
636 ///
637 /// ```
638 /// use fp_library::classes::filterable::Filterable;
639 /// use fp_library::brands::OptionBrand;
640 /// use fp_library::types::Pair;
641 ///
642 /// let x = Some(5);
643 /// let Pair(oks, errs) = OptionBrand::partition_map(|a| if a > 2 { Ok(a) } else { Err(a) }, x);
644 /// assert_eq!(oks, Some(5));
645 /// assert_eq!(errs, None);
646 /// ```
647 fn partition_map<'a, Func, A: 'a, E: 'a, O: 'a>(
648 func: Func,
649 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
650 ) -> Pair<
651 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
652 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
653 >
654 where
655 Func: Fn(A) -> Result<O, E> + 'a,
656 {
657 match fa {
658 Some(a) => match func(a) {
659 Ok(o) => Pair(Some(o), None),
660 Err(e) => Pair(None, Some(e)),
661 },
662 None => Pair(None, None),
663 }
664 }
665
666 /// Partitions an option based on a predicate.
667 ///
668 /// This method partitions an option based on a predicate.
669 ///
670 /// ### Type Signature
671 ///
672 /// `forall a. Filterable Option => (a -> bool) -> Option a -> (Option a, Option a)`
673 ///
674 /// ### Parameters
675 ///
676 /// * `func`: The predicate.
677 /// * `fa`: The option to partition.
678 ///
679 /// ### Returns
680 ///
681 /// A pair of options.
682 ///
683 /// ### Examples
684 ///
685 /// ```
686 /// use fp_library::classes::filterable::Filterable;
687 /// use fp_library::brands::OptionBrand;
688 /// use fp_library::types::Pair;
689 ///
690 /// let x = Some(5);
691 /// let Pair(satisfied, not_satisfied) = OptionBrand::partition(|a| a > 2, x);
692 /// assert_eq!(satisfied, Some(5));
693 /// assert_eq!(not_satisfied, None);
694 /// ```
695 fn partition<'a, Func, A: 'a + Clone>(
696 func: Func,
697 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
698 ) -> Pair<
699 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
700 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
701 >
702 where
703 Func: Fn(A) -> bool + 'a,
704 {
705 match fa {
706 Some(a) => {
707 if func(a.clone()) {
708 Pair(Some(a), None)
709 } else {
710 Pair(None, Some(a))
711 }
712 }
713 None => Pair(None, None),
714 }
715 }
716
717 /// Maps a function over an option and filters out `None` results.
718 ///
719 /// This method maps a function over an option and filters out `None` results.
720 ///
721 /// ### Type Signature
722 ///
723 /// `forall a b. Filterable Option => (a -> Option b) -> Option a -> Option b`
724 ///
725 /// ### Parameters
726 ///
727 /// * `func`: The function to apply.
728 /// * `fa`: The option to filter and map.
729 ///
730 /// ### Returns
731 ///
732 /// The filtered and mapped option.
733 ///
734 /// ### Examples
735 ///
736 /// ```
737 /// use fp_library::classes::filterable::Filterable;
738 /// use fp_library::brands::OptionBrand;
739 ///
740 /// let x = Some(5);
741 /// let y = OptionBrand::filter_map(|a| if a > 2 { Some(a * 2) } else { None }, x);
742 /// assert_eq!(y, Some(10));
743 /// ```
744 fn filter_map<'a, Func, A: 'a, B: 'a>(
745 func: Func,
746 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
747 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
748 where
749 Func: Fn(A) -> Option<B> + 'a,
750 {
751 fa.and_then(func)
752 }
753
754 /// Filters an option based on a predicate.
755 ///
756 /// This method filters an option based on a predicate.
757 ///
758 /// ### Type Signature
759 ///
760 /// `forall a. Filterable Option => (a -> bool) -> Option a -> Option a`
761 ///
762 /// ### Parameters
763 ///
764 /// * `func`: The predicate.
765 /// * `fa`: The option to filter.
766 ///
767 /// ### Returns
768 ///
769 /// The filtered option.
770 ///
771 /// ### Examples
772 ///
773 /// ```
774 /// use fp_library::classes::filterable::Filterable;
775 /// use fp_library::brands::OptionBrand;
776 ///
777 /// let x = Some(5);
778 /// let y = OptionBrand::filter(|a| a > 2, x);
779 /// assert_eq!(y, Some(5));
780 /// ```
781 fn filter<'a, Func, A: 'a + Clone>(
782 func: Func,
783 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
784 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
785 where
786 Func: Fn(A) -> bool + 'a,
787 {
788 fa.filter(|a| func(a.clone()))
789 }
790}
791
792impl Witherable for OptionBrand {}
793
794#[cfg(test)]
795mod tests {
796 use super::*;
797 use crate::{
798 brands::{ArcFnBrand, RcFnBrand},
799 classes::{
800 compactable::{compact, separate},
801 filterable::{filter, filter_map, partition, partition_map},
802 functor::map,
803 par_foldable::{par_fold_map, par_fold_right},
804 pointed::pure,
805 semiapplicative::apply,
806 semimonad::bind,
807 send_clonable_fn::new_send,
808 traversable::traverse,
809 witherable::{wilt, wither},
810 },
811 functions::{compose, identity},
812 };
813 use quickcheck_macros::quickcheck;
814
815 // Functor Laws
816
817 /// Tests the identity law for Functor.
818 #[quickcheck]
819 fn functor_identity(x: Option<i32>) -> bool {
820 map::<OptionBrand, _, _, _>(identity, x) == x
821 }
822
823 /// Tests the composition law for Functor.
824 #[quickcheck]
825 fn functor_composition(x: Option<i32>) -> bool {
826 let f = |x: i32| x.wrapping_add(1);
827 let g = |x: i32| x.wrapping_mul(2);
828 map::<OptionBrand, _, _, _>(compose(f, g), x)
829 == map::<OptionBrand, _, _, _>(f, map::<OptionBrand, _, _, _>(g, x))
830 }
831
832 // Applicative Laws
833
834 /// Tests the identity law for Applicative.
835 #[quickcheck]
836 fn applicative_identity(v: Option<i32>) -> bool {
837 apply::<RcFnBrand, OptionBrand, _, _>(
838 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
839 v,
840 ) == v
841 }
842
843 /// Tests the homomorphism law for Applicative.
844 #[quickcheck]
845 fn applicative_homomorphism(x: i32) -> bool {
846 let f = |x: i32| x.wrapping_mul(2);
847 apply::<RcFnBrand, OptionBrand, _, _>(
848 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
849 pure::<OptionBrand, _>(x),
850 ) == pure::<OptionBrand, _>(f(x))
851 }
852
853 /// Tests the composition law for Applicative.
854 #[quickcheck]
855 fn applicative_composition(
856 w: Option<i32>,
857 u_is_some: bool,
858 v_is_some: bool,
859 ) -> bool {
860 let v_fn = |x: i32| x.wrapping_mul(2);
861 let u_fn = |x: i32| x.wrapping_add(1);
862
863 let v = if v_is_some {
864 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn))
865 } else {
866 None
867 };
868 let u = if u_is_some {
869 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn))
870 } else {
871 None
872 };
873
874 // RHS: u <*> (v <*> w)
875 let vw = apply::<RcFnBrand, OptionBrand, _, _>(v.clone(), w.clone());
876 let rhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), vw);
877
878 // LHS: pure(compose) <*> u <*> v <*> w
879 // equivalent to (u . v) <*> w
880 let uv = match (u, v) {
881 (Some(uf), Some(vf)) => {
882 let composed = move |x| uf(vf(x));
883 Some(<RcFnBrand as ClonableFn>::new(composed))
884 }
885 _ => None,
886 };
887
888 let lhs = apply::<RcFnBrand, OptionBrand, _, _>(uv, w);
889
890 lhs == rhs
891 }
892
893 /// Tests the interchange law for Applicative.
894 #[quickcheck]
895 fn applicative_interchange(y: i32) -> bool {
896 // u <*> pure y = pure ($ y) <*> u
897 let f = |x: i32| x.wrapping_mul(2);
898 let u = pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f));
899
900 let lhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), pure::<OptionBrand, _>(y));
901
902 let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
903 let rhs = apply::<RcFnBrand, OptionBrand, _, _>(pure::<OptionBrand, _>(rhs_fn), u);
904
905 lhs == rhs
906 }
907
908 // Monad Laws
909
910 /// Tests the left identity law for Monad.
911 #[quickcheck]
912 fn monad_left_identity(a: i32) -> bool {
913 let f = |x: i32| Some(x.wrapping_mul(2));
914 bind::<OptionBrand, _, _, _>(pure::<OptionBrand, _>(a), f) == f(a)
915 }
916
917 /// Tests the right identity law for Monad.
918 #[quickcheck]
919 fn monad_right_identity(m: Option<i32>) -> bool {
920 bind::<OptionBrand, _, _, _>(m, pure::<OptionBrand, _>) == m
921 }
922
923 /// Tests the associativity law for Monad.
924 #[quickcheck]
925 fn monad_associativity(m: Option<i32>) -> bool {
926 let f = |x: i32| Some(x.wrapping_mul(2));
927 let g = |x: i32| Some(x.wrapping_add(1));
928 bind::<OptionBrand, _, _, _>(bind::<OptionBrand, _, _, _>(m, f), g)
929 == bind::<OptionBrand, _, _, _>(m, |x| bind::<OptionBrand, _, _, _>(f(x), g))
930 }
931
932 // Edge Cases
933
934 /// Tests `map` on `None`.
935 #[test]
936 fn map_none() {
937 assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x + 1, None), None);
938 }
939
940 /// Tests `bind` on `None`.
941 #[test]
942 fn bind_none() {
943 assert_eq!(bind::<OptionBrand, _, _, _>(None, |x: i32| Some(x + 1)), None);
944 }
945
946 /// Tests `bind` returning `None`.
947 #[test]
948 fn bind_returning_none() {
949 assert_eq!(bind::<OptionBrand, _, _, _>(Some(5), |_| None::<i32>), None);
950 }
951
952 /// Tests `fold_right` on `None`.
953 #[test]
954 fn fold_right_none() {
955 assert_eq!(
956 crate::classes::foldable::fold_right::<RcFnBrand, OptionBrand, _, _, _>(
957 |x: i32, acc| x + acc,
958 0,
959 None
960 ),
961 0
962 );
963 }
964
965 /// Tests `fold_left` on `None`.
966 #[test]
967 fn fold_left_none() {
968 assert_eq!(
969 crate::classes::foldable::fold_left::<RcFnBrand, OptionBrand, _, _, _>(
970 |acc, x: i32| acc + x,
971 0,
972 None
973 ),
974 0
975 );
976 }
977
978 /// Tests `traverse` on `None`.
979 #[test]
980 fn traverse_none() {
981 assert_eq!(
982 crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
983 |x: i32| Some(x + 1),
984 None
985 ),
986 Some(None)
987 );
988 }
989
990 /// Tests `traverse` returning `None`.
991 #[test]
992 fn traverse_returning_none() {
993 assert_eq!(
994 crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
995 |_: i32| None::<i32>,
996 Some(5)
997 ),
998 None
999 );
1000 }
1001
1002 // ParFoldable Tests
1003
1004 /// Tests `par_fold_map` on `None`.
1005 #[test]
1006 fn par_fold_map_none() {
1007 let x: Option<i32> = None;
1008 let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
1009 assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "".to_string());
1010 }
1011
1012 /// Tests `par_fold_map` on `Some`.
1013 #[test]
1014 fn par_fold_map_some() {
1015 let x = Some(5);
1016 let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
1017 assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "5".to_string());
1018 }
1019
1020 /// Tests `par_fold_right` on `Some`.
1021 #[test]
1022 fn par_fold_right_some() {
1023 let x = Some(5);
1024 let f = new_send::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
1025 assert_eq!(par_fold_right::<ArcFnBrand, OptionBrand, _, _>(f, 10, x), 15);
1026 }
1027
1028 // Filterable Laws
1029
1030 /// Tests `filterMap identity ≡ compact`.
1031 #[quickcheck]
1032 fn filterable_filter_map_identity(x: Option<Option<i32>>) -> bool {
1033 filter_map::<OptionBrand, _, _, _>(identity, x.clone()) == compact::<OptionBrand, _>(x)
1034 }
1035
1036 /// Tests `filterMap Just ≡ identity`.
1037 #[quickcheck]
1038 fn filterable_filter_map_just(x: Option<i32>) -> bool {
1039 filter_map::<OptionBrand, _, _, _>(Some, x.clone()) == x
1040 }
1041
1042 /// Tests `filterMap (l <=< r) ≡ filterMap l <<< filterMap r`.
1043 #[quickcheck]
1044 fn filterable_filter_map_composition(x: Option<i32>) -> bool {
1045 let r = |i: i32| if i % 2 == 0 { Some(i) } else { None };
1046 let l = |i: i32| if i > 5 { Some(i) } else { None };
1047 let composed = |i| r(i).and_then(l);
1048
1049 filter_map::<OptionBrand, _, _, _>(composed, x.clone())
1050 == filter_map::<OptionBrand, _, _, _>(l, filter_map::<OptionBrand, _, _, _>(r, x))
1051 }
1052
1053 /// Tests `filter ≡ filterMap <<< maybeBool`.
1054 #[quickcheck]
1055 fn filterable_filter_consistency(x: Option<i32>) -> bool {
1056 let p = |i: i32| i % 2 == 0;
1057 let maybe_bool = |i| if p(i) { Some(i) } else { None };
1058
1059 filter::<OptionBrand, _, _>(p, x.clone())
1060 == filter_map::<OptionBrand, _, _, _>(maybe_bool, x)
1061 }
1062
1063 /// Tests `partitionMap identity ≡ separate`.
1064 #[quickcheck]
1065 fn filterable_partition_map_identity(x: Option<Result<i32, i32>>) -> bool {
1066 partition_map::<OptionBrand, _, _, _, _>(identity, x.clone())
1067 == separate::<OptionBrand, _, _>(x)
1068 }
1069
1070 /// Tests `partitionMap Right ≡ identity` (on the right side).
1071 #[quickcheck]
1072 fn filterable_partition_map_right_identity(x: Option<i32>) -> bool {
1073 let Pair(oks, _) = partition_map::<OptionBrand, _, _, _, _>(Ok::<_, i32>, x.clone());
1074 oks == x
1075 }
1076
1077 /// Tests `partitionMap Left ≡ identity` (on the left side).
1078 #[quickcheck]
1079 fn filterable_partition_map_left_identity(x: Option<i32>) -> bool {
1080 let Pair(_, errs) = partition_map::<OptionBrand, _, _, _, _>(Err::<i32, _>, x.clone());
1081 errs == x
1082 }
1083
1084 /// Tests `f <<< partition ≡ partitionMap <<< eitherBool`.
1085 #[quickcheck]
1086 fn filterable_partition_consistency(x: Option<i32>) -> bool {
1087 let p = |i: i32| i % 2 == 0;
1088 let either_bool = |i| if p(i) { Ok(i) } else { Err(i) };
1089
1090 let Pair(satisfied, not_satisfied) = partition::<OptionBrand, _, _>(p, x.clone());
1091 let Pair(oks, errs) = partition_map::<OptionBrand, _, _, _, _>(either_bool, x);
1092
1093 satisfied == oks && not_satisfied == errs
1094 }
1095
1096 // Witherable Laws
1097
1098 /// Tests `wither (pure <<< Just) ≡ pure`.
1099 #[quickcheck]
1100 fn witherable_identity(x: Option<i32>) -> bool {
1101 wither::<OptionBrand, _, OptionBrand, _, _>(|i| Some(Some(i)), x.clone()) == Some(x)
1102 }
1103
1104 /// Tests `wilt p ≡ map separate <<< traverse p`.
1105 #[quickcheck]
1106 fn witherable_wilt_consistency(x: Option<i32>) -> bool {
1107 let p = |i: i32| Some(if i % 2 == 0 { Ok(i) } else { Err(i) });
1108
1109 let lhs = wilt::<OptionBrand, _, OptionBrand, _, _, _>(p, x.clone());
1110 let rhs = map::<OptionBrand, _, _, _>(
1111 |res| separate::<OptionBrand, _, _>(res),
1112 traverse::<OptionBrand, OptionBrand, _, _, _>(p, x),
1113 );
1114
1115 lhs == rhs
1116 }
1117
1118 /// Tests `wither p ≡ map compact <<< traverse p`.
1119 #[quickcheck]
1120 fn witherable_wither_consistency(x: Option<i32>) -> bool {
1121 let p = |i: i32| Some(if i % 2 == 0 { Some(i) } else { None });
1122
1123 let lhs = wither::<OptionBrand, _, OptionBrand, _, _>(p, x.clone());
1124 let rhs = map::<OptionBrand, _, _, _>(
1125 |opt| compact::<OptionBrand, _>(opt),
1126 traverse::<OptionBrand, OptionBrand, _, _, _>(p, x),
1127 );
1128
1129 lhs == rhs
1130 }
1131
1132 // Edge Cases
1133
1134 /// Tests `compact` on `Some(None)`.
1135 #[test]
1136 fn compact_some_none() {
1137 assert_eq!(compact::<OptionBrand, _>(Some(None::<i32>)), None);
1138 }
1139
1140 /// Tests `compact` on `Some(Some(x))`.
1141 #[test]
1142 fn compact_some_some() {
1143 assert_eq!(compact::<OptionBrand, _>(Some(Some(5))), Some(5));
1144 }
1145
1146 /// Tests `compact` on `None`.
1147 #[test]
1148 fn compact_none() {
1149 assert_eq!(compact::<OptionBrand, _>(None::<Option<i32>>), None);
1150 }
1151
1152 /// Tests `separate` on `Some(Ok(x))`.
1153 #[test]
1154 fn separate_some_ok() {
1155 let Pair(oks, errs) = separate::<OptionBrand, _, _>(Some(Ok::<i32, &str>(5)));
1156 assert_eq!(oks, Some(5));
1157 assert_eq!(errs, None);
1158 }
1159
1160 /// Tests `separate` on `Some(Err(e))`.
1161 #[test]
1162 fn separate_some_err() {
1163 let Pair(oks, errs) = separate::<OptionBrand, _, _>(Some(Err::<i32, &str>("error")));
1164 assert_eq!(oks, None);
1165 assert_eq!(errs, Some("error"));
1166 }
1167
1168 /// Tests `separate` on `None`.
1169 #[test]
1170 fn separate_none() {
1171 let Pair(oks, errs) = separate::<OptionBrand, _, _>(None::<Result<i32, &str>>);
1172 assert_eq!(oks, None);
1173 assert_eq!(errs, None);
1174 }
1175
1176 /// Tests `partition_map` on `None`.
1177 #[test]
1178 fn partition_map_none() {
1179 let Pair(oks, errs) =
1180 partition_map::<OptionBrand, _, _, _, _>(|x: i32| Ok::<i32, i32>(x), None::<i32>);
1181 assert_eq!(oks, None);
1182 assert_eq!(errs, None);
1183 }
1184
1185 /// Tests `partition` on `None`.
1186 #[test]
1187 fn partition_none() {
1188 let Pair(satisfied, not_satisfied) =
1189 partition::<OptionBrand, _, _>(|x: i32| x > 0, None::<i32>);
1190 assert_eq!(satisfied, None);
1191 assert_eq!(not_satisfied, None);
1192 }
1193
1194 /// Tests `filter_map` on `None`.
1195 #[test]
1196 fn filter_map_none() {
1197 assert_eq!(filter_map::<OptionBrand, _, _, _>(|x: i32| Some(x), None::<i32>), None);
1198 }
1199
1200 /// Tests `filter` on `None`.
1201 #[test]
1202 fn filter_none() {
1203 assert_eq!(filter::<OptionBrand, _, _>(|x: i32| x > 0, None::<i32>), None);
1204 }
1205
1206 /// Tests `wilt` on `None`.
1207 #[test]
1208 fn wilt_none() {
1209 let res = wilt::<OptionBrand, _, OptionBrand, _, _, _>(
1210 |x: i32| Some(Ok::<i32, i32>(x)),
1211 None::<i32>,
1212 );
1213 assert_eq!(res, Some(Pair(None, None)));
1214 }
1215
1216 /// Tests `wither` on `None`.
1217 #[test]
1218 fn wither_none() {
1219 let res = wither::<OptionBrand, _, OptionBrand, _, _>(|x: i32| Some(Some(x)), None::<i32>);
1220 assert_eq!(res, Some(None));
1221 }
1222}