1#[fp_macros::document_module]
6mod inner {
7 use {
8 crate::{
9 Apply,
10 brands::{
11 TryThunkBrand,
12 TryThunkErrAppliedBrand,
13 TryThunkOkAppliedBrand,
14 },
15 classes::{
16 ApplyFirst,
17 ApplySecond,
18 Bifunctor,
19 CloneableFn,
20 Deferrable,
21 Foldable,
22 Functor,
23 Lift,
24 MonadRec,
25 Monoid,
26 Pointed,
27 Semiapplicative,
28 Semigroup,
29 Semimonad,
30 },
31 impl_kind,
32 kinds::*,
33 types::{
34 Lazy,
35 LazyConfig,
36 Step,
37 Thunk,
38 TryLazy,
39 },
40 },
41 fp_macros::*,
42 };
43
44 #[document_type_parameters(
49 "The lifetime of the computation.",
50 "The type of the value produced by the computation on success.",
51 "The type of the error produced by the computation on failure."
52 )]
53 #[document_fields("The closure that performs the computation.")]
61 pub struct TryThunk<'a, A, E>(Box<dyn FnOnce() -> Result<A, E> + 'a>);
63
64 #[document_type_parameters(
65 "The lifetime of the computation.",
66 "The type of the success value.",
67 "The type of the error value."
68 )]
69 #[document_parameters("The `TryThunk` instance.")]
70 impl<'a, A: 'a, E: 'a> TryThunk<'a, A, E> {
71 #[document_signature]
73 #[document_parameters("The thunk to wrap.")]
75 #[document_returns("A new `TryThunk` instance.")]
77 #[document_examples]
79 pub fn new(f: impl FnOnce() -> Result<A, E> + 'a) -> Self {
87 TryThunk(Box::new(f))
88 }
89
90 #[document_signature]
92 #[document_parameters("The value to wrap.")]
94 #[document_returns("A new `TryThunk` instance containing the value.")]
96 #[document_examples]
98 pub fn pure(a: A) -> Self
106 where
107 A: 'a, {
108 TryThunk::new(move || Ok(a))
109 }
110
111 #[document_signature]
113 #[document_parameters("The thunk that returns a `TryThunk`.")]
115 #[document_returns("A new `TryThunk` instance.")]
117 #[document_examples]
119 pub fn defer(f: impl FnOnce() -> TryThunk<'a, A, E> + 'a) -> Self {
127 TryThunk::new(move || f().evaluate())
128 }
129
130 #[document_signature]
134 #[document_parameters("The value to wrap.")]
136 #[document_returns("A new `TryThunk` instance containing the value.")]
138 #[document_examples]
140 pub fn ok(a: A) -> Self
148 where
149 A: 'a, {
150 Self::pure(a)
151 }
152
153 #[document_signature]
155 #[document_parameters("The error to wrap.")]
157 #[document_returns("A new `TryThunk` instance containing the error.")]
159 #[document_examples]
161 pub fn err(e: E) -> Self
169 where
170 E: 'a, {
171 TryThunk::new(move || Err(e))
172 }
173
174 #[document_signature]
176 #[document_type_parameters("The type of the result of the new computation.")]
178 #[document_parameters("The function to apply to the result of the computation.")]
180 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
182 #[document_examples]
184 pub fn bind<B: 'a>(
192 self,
193 f: impl FnOnce(A) -> TryThunk<'a, B, E> + 'a,
194 ) -> TryThunk<'a, B, E> {
195 TryThunk::new(move || match (self.0)() {
196 Ok(a) => (f(a).0)(),
197 Err(e) => Err(e),
198 })
199 }
200
201 #[document_signature]
203 #[document_type_parameters("The type of the result of the transformation.")]
205 #[document_parameters("The function to apply to the result of the computation.")]
207 #[document_returns("A new `TryThunk` instance with the transformed result.")]
209 #[document_examples]
211 pub fn map<B: 'a>(
219 self,
220 func: impl FnOnce(A) -> B + 'a,
221 ) -> TryThunk<'a, B, E> {
222 TryThunk::new(move || (self.0)().map(func))
223 }
224
225 #[document_signature]
227 #[document_type_parameters("The type of the new error.")]
229 #[document_parameters("The function to apply to the error.")]
231 #[document_returns("A new `TryThunk` instance with the transformed error.")]
233 #[document_examples]
235 pub fn map_err<E2: 'a>(
243 self,
244 f: impl FnOnce(E) -> E2 + 'a,
245 ) -> TryThunk<'a, A, E2> {
246 TryThunk::new(move || (self.0)().map_err(f))
247 }
248
249 #[document_signature]
251 #[document_parameters("The function to apply to the error value.")]
253 #[document_returns("A new `TryThunk` that attempts to recover from failure.")]
255 #[document_examples]
257 pub fn catch(
265 self,
266 f: impl FnOnce(E) -> TryThunk<'a, A, E> + 'a,
267 ) -> Self {
268 TryThunk::new(move || match (self.0)() {
269 Ok(a) => Ok(a),
270 Err(e) => (f(e).0)(),
271 })
272 }
273
274 #[document_signature]
276 #[document_returns("The result of the computation.")]
278 #[document_examples]
280 pub fn evaluate(self) -> Result<A, E> {
288 (self.0)()
289 }
290 }
291
292 #[document_type_parameters(
293 "The lifetime of the computation.",
294 "The type of the success value.",
295 "The type of the error value.",
296 "The memoization configuration."
297 )]
298 impl<'a, A, E, Config> From<Lazy<'a, A, Config>> for TryThunk<'a, A, E>
299 where
300 A: Clone + 'a,
301 E: 'a,
302 Config: LazyConfig,
303 {
304 #[document_signature]
305 #[document_parameters("The lazy value to convert.")]
306 #[document_returns("A new `TryThunk` instance that wraps the lazy value.")]
307 #[document_examples]
308 fn from(memo: Lazy<'a, A, Config>) -> Self {
316 TryThunk::new(move || Ok(memo.evaluate().clone()))
317 }
318 }
319
320 #[document_type_parameters(
321 "The lifetime of the computation.",
322 "The type of the success value.",
323 "The type of the error value.",
324 "The memoization configuration."
325 )]
326 impl<'a, A, E, Config> From<TryLazy<'a, A, E, Config>> for TryThunk<'a, A, E>
327 where
328 A: Clone + 'a,
329 E: Clone + 'a,
330 Config: LazyConfig,
331 {
332 #[document_signature]
333 #[document_parameters("The fallible lazy value to convert.")]
334 #[document_returns("A new `TryThunk` instance that wraps the fallible lazy value.")]
335 #[document_examples]
336 fn from(memo: TryLazy<'a, A, E, Config>) -> Self {
344 TryThunk::new(move || memo.evaluate().cloned().map_err(Clone::clone))
345 }
346 }
347
348 #[document_type_parameters(
349 "The lifetime of the computation.",
350 "The type of the success value.",
351 "The type of the error value."
352 )]
353 impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E> {
354 #[document_signature]
355 #[document_parameters("The thunk to convert.")]
356 #[document_returns("A new `TryThunk` instance that wraps the thunk.")]
357 #[document_examples]
358 fn from(eval: Thunk<'a, A>) -> Self {
366 TryThunk::new(move || Ok(eval.evaluate()))
367 }
368 }
369
370 #[document_type_parameters(
371 "The lifetime of the computation.",
372 "The type of the success value.",
373 "The type of the error value."
374 )]
375 impl<'a, A, E> Deferrable<'a> for TryThunk<'a, A, E>
376 where
377 A: 'a,
378 E: 'a,
379 {
380 #[document_signature]
382 #[document_parameters("A thunk that produces the try thunk.")]
384 #[document_returns("The deferred try thunk.")]
386 #[document_examples]
388 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
401 where
402 Self: Sized, {
403 TryThunk::defer(f)
404 }
405 }
406
407 impl_kind! {
408 impl<E: 'static> for TryThunkErrAppliedBrand<E> {
409 #[document_default]
410 type Of<'a, A: 'a>: 'a = TryThunk<'a, A, E>;
411 }
412 }
413
414 #[document_type_parameters("The error type.")]
415 impl<E: 'static> Functor for TryThunkErrAppliedBrand<E> {
416 #[document_signature]
418 #[document_type_parameters(
420 "The lifetime of the computation.",
421 "The type of the value inside the `TryThunk`.",
422 "The type of the result of the transformation."
423 )]
424 #[document_parameters(
426 "The function to apply to the result of the computation.",
427 "The `TryThunk` instance."
428 )]
429 #[document_returns("A new `TryThunk` instance with the transformed result.")]
431 #[document_examples]
432 fn map<'a, A: 'a, B: 'a>(
445 func: impl Fn(A) -> B + 'a,
446 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
447 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
448 fa.map(func)
449 }
450 }
451
452 #[document_type_parameters("The error type.")]
453 impl<E: 'static> Pointed for TryThunkErrAppliedBrand<E> {
454 #[document_signature]
456 #[document_type_parameters(
458 "The lifetime of the computation.",
459 "The type of the value to wrap."
460 )]
461 #[document_parameters("The value to wrap.")]
463 #[document_returns("A new `TryThunk` instance containing the value.")]
465 #[document_examples]
467 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
479 TryThunk::pure(a)
480 }
481 }
482
483 #[document_type_parameters("The error type.")]
484 impl<E: 'static> Lift for TryThunkErrAppliedBrand<E> {
485 #[document_signature]
487 #[document_type_parameters(
489 "The lifetime of the computation.",
490 "The type of the first value.",
491 "The type of the second value.",
492 "The type of the result."
493 )]
494 #[document_parameters(
496 "The binary function to apply.",
497 "The first `TryThunk`.",
498 "The second `TryThunk`."
499 )]
500 #[document_returns(
502 "A new `TryThunk` instance containing the result of applying the function."
503 )]
504 #[document_examples]
505 fn lift2<'a, A, B, C>(
519 func: impl Fn(A, B) -> C + 'a,
520 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
521 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
522 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
523 where
524 A: Clone + 'a,
525 B: Clone + 'a,
526 C: 'a, {
527 fa.bind(move |a| fb.map(move |b| func(a, b)))
528 }
529 }
530
531 #[document_type_parameters("The error type.")]
532 impl<E: 'static> ApplyFirst for TryThunkErrAppliedBrand<E> {}
533
534 #[document_type_parameters("The error type.")]
535 impl<E: 'static> ApplySecond for TryThunkErrAppliedBrand<E> {}
536
537 #[document_type_parameters("The error type.")]
538 impl<E: 'static> Semiapplicative for TryThunkErrAppliedBrand<E> {
539 #[document_signature]
541 #[document_type_parameters(
543 "The lifetime of the computation.",
544 "The brand of the cloneable function wrapper.",
545 "The type of the input.",
546 "The type of the result."
547 )]
548 #[document_parameters(
550 "The `TryThunk` containing the function.",
551 "The `TryThunk` containing the value."
552 )]
553 #[document_returns(
555 "A new `TryThunk` instance containing the result of applying the function."
556 )]
557 #[document_examples]
558 fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
573 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
574 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
575 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
576 ff.bind(move |f| {
577 fa.map(
578 #[allow(clippy::redundant_closure)] move |a| f(a),
580 )
581 })
582 }
583 }
584
585 #[document_type_parameters("The error type.")]
586 impl<E: 'static> Semimonad for TryThunkErrAppliedBrand<E> {
587 #[document_signature]
589 #[document_type_parameters(
591 "The lifetime of the computation.",
592 "The type of the result of the first computation.",
593 "The type of the result of the new computation."
594 )]
595 #[document_parameters(
597 "The first `TryThunk`.",
598 "The function to apply to the result of the computation."
599 )]
600 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
602 #[document_examples]
603 fn bind<'a, A: 'a, B: 'a>(
618 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
619 func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
620 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
621 ma.bind(func)
622 }
623 }
624
625 #[document_type_parameters("The error type.")]
626 impl<E: 'static> MonadRec for TryThunkErrAppliedBrand<E> {
627 #[document_signature]
629 #[document_type_parameters(
631 "The lifetime of the computation.",
632 "The type of the initial value and loop state.",
633 "The type of the result."
634 )]
635 #[document_parameters("The step function.", "The initial value.")]
637 #[document_returns("The result of the computation.")]
639 #[document_examples]
641 fn tail_rec_m<'a, A: 'a, B: 'a>(
661 f: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Step<A, B>>)
662 + Clone
663 + 'a,
664 a: A,
665 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
666 TryThunk::new(move || {
667 let mut current = a;
668 loop {
669 match f(current).evaluate() {
670 Ok(Step::Loop(next)) => current = next,
671 Ok(Step::Done(res)) => break Ok(res),
672 Err(e) => break Err(e),
673 }
674 }
675 })
676 }
677 }
678
679 #[document_type_parameters("The error type.")]
680 impl<E: 'static> Foldable for TryThunkErrAppliedBrand<E> {
681 #[document_signature]
683 #[document_type_parameters(
685 "The lifetime of the computation.",
686 "The brand of the cloneable function to use.",
687 "The type of the elements in the structure.",
688 "The type of the accumulator."
689 )]
690 #[document_parameters(
692 "The function to apply to each element and the accumulator.",
693 "The initial value of the accumulator.",
694 "The `TryThunk` to fold."
695 )]
696 #[document_returns("The final accumulator value.")]
698 #[document_examples]
699 fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
713 func: impl Fn(A, B) -> B + 'a,
714 initial: B,
715 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
716 ) -> B
717 where
718 FnBrand: CloneableFn + 'a, {
719 match fa.evaluate() {
720 Ok(a) => func(a, initial),
721 Err(_) => initial,
722 }
723 }
724
725 #[document_signature]
727 #[document_type_parameters(
729 "The lifetime of the computation.",
730 "The brand of the cloneable function to use.",
731 "The type of the elements in the structure.",
732 "The type of the accumulator."
733 )]
734 #[document_parameters(
736 "The function to apply to the accumulator and each element.",
737 "The initial value of the accumulator.",
738 "The `TryThunk` to fold."
739 )]
740 #[document_returns("The final accumulator value.")]
742 #[document_examples]
743 fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
757 func: impl Fn(B, A) -> B + 'a,
758 initial: B,
759 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
760 ) -> B
761 where
762 FnBrand: CloneableFn + 'a, {
763 match fa.evaluate() {
764 Ok(a) => func(initial, a),
765 Err(_) => initial,
766 }
767 }
768
769 #[document_signature]
771 #[document_type_parameters(
773 "The lifetime of the computation.",
774 "The brand of the cloneable function to use.",
775 "The type of the elements in the structure.",
776 "The type of the monoid."
777 )]
778 #[document_parameters("The mapping function.", "The Thunk to fold.")]
780 #[document_returns("The monoid value.")]
782 #[document_examples]
784 fn fold_map<'a, FnBrand, A: 'a + Clone, M>(
798 func: impl Fn(A) -> M + 'a,
799 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
800 ) -> M
801 where
802 M: Monoid + 'a,
803 FnBrand: CloneableFn + 'a, {
804 match fa.evaluate() {
805 Ok(a) => func(a),
806 Err(_) => M::empty(),
807 }
808 }
809 }
810
811 #[document_type_parameters(
812 "The lifetime of the computation.",
813 "The success value type.",
814 "The error value type."
815 )]
816 impl<'a, A: Semigroup + 'a, E: 'a> Semigroup for TryThunk<'a, A, E> {
817 #[document_signature]
819 #[document_parameters("The first `TryThunk`.", "The second `TryThunk`.")]
821 #[document_returns("A new `TryThunk` containing the combined result.")]
823 #[document_examples]
825 fn append(
840 a: Self,
841 b: Self,
842 ) -> Self {
843 TryThunk::new(move || match (a.evaluate(), b.evaluate()) {
844 (Ok(a_val), Ok(b_val)) => Ok(Semigroup::append(a_val, b_val)),
845 (Err(e), _) => Err(e),
846 (_, Err(e)) => Err(e),
847 })
848 }
849 }
850
851 #[document_type_parameters(
852 "The lifetime of the computation.",
853 "The success value type.",
854 "The error value type."
855 )]
856 impl<'a, A: Monoid + 'a, E: 'a> Monoid for TryThunk<'a, A, E> {
857 #[document_signature]
859 #[document_returns("A `TryThunk` producing the identity value of `A`.")]
861 #[document_examples]
863 fn empty() -> Self {
874 TryThunk::new(|| Ok(Monoid::empty()))
875 }
876 }
877
878 impl_kind! {
879 for TryThunkBrand {
886 type Of<'a, E: 'a, A: 'a>: 'a = TryThunk<'a, A, E>;
887 }
888 }
889
890 impl Bifunctor for TryThunkBrand {
891 #[document_signature]
895 #[document_type_parameters(
897 "The lifetime of the values.",
898 "The type of the error value.",
899 "The type of the mapped error value.",
900 "The type of the success value.",
901 "The type of the mapped success value."
902 )]
903 #[document_parameters(
905 "The function to apply to the error.",
906 "The function to apply to the success.",
907 "The `TryThunk` to map over."
908 )]
909 #[document_returns("A new `TryThunk` containing the mapped values.")]
911 #[document_examples]
912 fn bimap<'a, A: 'a, B: 'a, C: 'a, D: 'a>(
928 f: impl Fn(A) -> B + 'a,
929 g: impl Fn(C) -> D + 'a,
930 p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
931 ) -> Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, D>) {
932 TryThunk::new(move || match p.evaluate() {
933 Ok(c) => Ok(g(c)),
934 Err(a) => Err(f(a)),
935 })
936 }
937 }
938
939 impl_kind! {
940 impl<A: 'static> for TryThunkOkAppliedBrand<A> {
941 #[document_default]
942 type Of<'a, E: 'a>: 'a = TryThunk<'a, A, E>;
943 }
944 }
945
946 #[document_type_parameters("The success type.")]
947 impl<A: 'static> Functor for TryThunkOkAppliedBrand<A> {
948 #[document_signature]
950 #[document_type_parameters(
952 "The lifetime of the computation.",
953 "The type of the error value inside the `TryThunk`.",
954 "The type of the result of the transformation."
955 )]
956 #[document_parameters("The function to apply to the error.", "The `TryThunk` instance.")]
958 #[document_returns("A new `TryThunk` instance with the transformed error.")]
960 #[document_examples]
962 fn map<'a, E: 'a, E2: 'a>(
975 func: impl Fn(E) -> E2 + 'a,
976 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
977 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
978 fa.map_err(func)
979 }
980 }
981
982 #[document_type_parameters("The success type.")]
983 impl<A: 'static> Pointed for TryThunkOkAppliedBrand<A> {
984 #[document_signature]
986 #[document_type_parameters(
988 "The lifetime of the computation.",
989 "The type of the value to wrap."
990 )]
991 #[document_parameters("The value to wrap.")]
993 #[document_returns("A new `TryThunk` instance containing the value as an error.")]
995 #[document_examples]
997 fn pure<'a, E: 'a>(e: E) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>) {
1009 TryThunk::err(e)
1010 }
1011 }
1012
1013 #[document_type_parameters("The success type.")]
1014 impl<A: 'static> Lift for TryThunkOkAppliedBrand<A> {
1015 #[document_signature]
1017 #[document_type_parameters(
1019 "The lifetime of the computation.",
1020 "The type of the first error value.",
1021 "The type of the second error value.",
1022 "The type of the result error value."
1023 )]
1024 #[document_parameters(
1026 "The binary function to apply to the errors.",
1027 "The first `TryThunk`.",
1028 "The second `TryThunk`."
1029 )]
1030 #[document_returns(
1032 "A new `TryThunk` instance containing the result of applying the function to the errors."
1033 )]
1034 #[document_examples]
1035 fn lift2<'a, E1, E2, E3>(
1049 func: impl Fn(E1, E2) -> E3 + 'a,
1050 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1051 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>),
1052 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E3>)
1053 where
1054 E1: Clone + 'a,
1055 E2: Clone + 'a,
1056 E3: 'a, {
1057 TryThunk::new(move || match (fa.evaluate(), fb.evaluate()) {
1058 (Err(e1), Err(e2)) => Err(func(e1, e2)),
1059 (Ok(a), _) => Ok(a),
1060 (_, Ok(a)) => Ok(a),
1061 })
1062 }
1063 }
1064
1065 #[document_type_parameters("The success type.")]
1066 impl<A: 'static> ApplyFirst for TryThunkOkAppliedBrand<A> {}
1067
1068 #[document_type_parameters("The success type.")]
1069 impl<A: 'static> ApplySecond for TryThunkOkAppliedBrand<A> {}
1070
1071 #[document_type_parameters("The success type.")]
1072 impl<A: 'static> Semiapplicative for TryThunkOkAppliedBrand<A> {
1073 #[document_signature]
1075 #[document_type_parameters(
1077 "The lifetime of the computation.",
1078 "The brand of the cloneable function wrapper.",
1079 "The type of the input error.",
1080 "The type of the result error."
1081 )]
1082 #[document_parameters(
1084 "The `TryThunk` containing the function (in Err).",
1085 "The `TryThunk` containing the value (in Err)."
1086 )]
1087 #[document_returns(
1089 "A new `TryThunk` instance containing the result of applying the function."
1090 )]
1091 #[document_examples]
1092 fn apply<'a, FnBrand: 'a + CloneableFn, E1: 'a + Clone, E2: 'a>(
1107 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, E1, E2>>),
1108 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1109 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1110 TryThunk::new(move || match (ff.evaluate(), fa.evaluate()) {
1111 (Err(f), Err(e)) => Err(f(e)),
1112 (Ok(a), _) => Ok(a),
1113 (_, Ok(a)) => Ok(a),
1114 })
1115 }
1116 }
1117
1118 #[document_type_parameters("The success type.")]
1119 impl<A: 'static> Semimonad for TryThunkOkAppliedBrand<A> {
1120 #[document_signature]
1122 #[document_type_parameters(
1124 "The lifetime of the computation.",
1125 "The type of the result of the first computation (error).",
1126 "The type of the result of the new computation (error)."
1127 )]
1128 #[document_parameters(
1130 "The first `TryThunk`.",
1131 "The function to apply to the error result of the computation."
1132 )]
1133 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
1135 #[document_examples]
1136 fn bind<'a, E1: 'a, E2: 'a>(
1151 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1152 func: impl Fn(E1) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) + 'a,
1153 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1154 TryThunk::new(move || match ma.evaluate() {
1155 Ok(a) => Ok(a),
1156 Err(e) => func(e).evaluate(),
1157 })
1158 }
1159 }
1160
1161 #[document_type_parameters("The success type.")]
1162 impl<A: 'static> Foldable for TryThunkOkAppliedBrand<A> {
1163 #[document_signature]
1165 #[document_type_parameters(
1167 "The lifetime of the computation.",
1168 "The brand of the cloneable function to use.",
1169 "The type of the elements in the structure.",
1170 "The type of the accumulator."
1171 )]
1172 #[document_parameters(
1174 "The function to apply to each element and the accumulator.",
1175 "The initial value of the accumulator.",
1176 "The `TryThunk` to fold."
1177 )]
1178 #[document_returns("The final accumulator value.")]
1180 #[document_examples]
1181 fn fold_right<'a, FnBrand, E: 'a + Clone, B: 'a>(
1195 func: impl Fn(E, B) -> B + 'a,
1196 initial: B,
1197 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1198 ) -> B
1199 where
1200 FnBrand: CloneableFn + 'a, {
1201 match fa.evaluate() {
1202 Err(e) => func(e, initial),
1203 Ok(_) => initial,
1204 }
1205 }
1206
1207 #[document_signature]
1209 #[document_type_parameters(
1211 "The lifetime of the computation.",
1212 "The brand of the cloneable function to use.",
1213 "The type of the elements in the structure.",
1214 "The type of the accumulator."
1215 )]
1216 #[document_parameters(
1218 "The function to apply to the accumulator and each element.",
1219 "The initial value of the accumulator.",
1220 "The `TryThunk` to fold."
1221 )]
1222 #[document_returns("The final accumulator value.")]
1224 #[document_examples]
1225 fn fold_left<'a, FnBrand, E: 'a + Clone, B: 'a>(
1239 func: impl Fn(B, E) -> B + 'a,
1240 initial: B,
1241 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1242 ) -> B
1243 where
1244 FnBrand: CloneableFn + 'a, {
1245 match fa.evaluate() {
1246 Err(e) => func(initial, e),
1247 Ok(_) => initial,
1248 }
1249 }
1250
1251 #[document_signature]
1253 #[document_type_parameters(
1255 "The lifetime of the computation.",
1256 "The brand of the cloneable function to use.",
1257 "The type of the elements in the structure.",
1258 "The type of the monoid."
1259 )]
1260 #[document_parameters("The mapping function.", "The Thunk to fold.")]
1262 #[document_returns("The monoid value.")]
1264 #[document_examples]
1266 fn fold_map<'a, FnBrand, E: 'a + Clone, M>(
1280 func: impl Fn(E) -> M + 'a,
1281 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1282 ) -> M
1283 where
1284 M: Monoid + 'a,
1285 FnBrand: CloneableFn + 'a, {
1286 match fa.evaluate() {
1287 Err(e) => func(e),
1288 Ok(_) => M::empty(),
1289 }
1290 }
1291 }
1292}
1293pub use inner::*;
1294
1295#[cfg(test)]
1296mod tests {
1297 use {
1298 super::*,
1299 crate::types::Thunk,
1300 };
1301
1302 #[test]
1306 fn test_success() {
1307 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
1308 assert_eq!(try_thunk.evaluate(), Ok(42));
1309 }
1310
1311 #[test]
1315 fn test_failure() {
1316 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error");
1317 assert_eq!(try_thunk.evaluate(), Err("error"));
1318 }
1319
1320 #[test]
1324 fn test_map() {
1325 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).map(|x| x * 2);
1326 assert_eq!(try_thunk.evaluate(), Ok(42));
1327 }
1328
1329 #[test]
1333 fn test_map_err() {
1334 let try_thunk: TryThunk<i32, i32> = TryThunk::err(21).map_err(|x| x * 2);
1335 assert_eq!(try_thunk.evaluate(), Err(42));
1336 }
1337
1338 #[test]
1342 fn test_bind() {
1343 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).bind(|x| TryThunk::pure(x * 2));
1344 assert_eq!(try_thunk.evaluate(), Ok(42));
1345 }
1346
1347 #[test]
1351 fn test_borrowing() {
1352 let x = 42;
1353 let try_thunk: TryThunk<&i32, ()> = TryThunk::new(|| Ok(&x));
1354 assert_eq!(try_thunk.evaluate(), Ok(&42));
1355 }
1356
1357 #[test]
1361 fn test_bind_failure() {
1362 let try_thunk = TryThunk::<i32, &str>::err("error").bind(|x| TryThunk::pure(x * 2));
1363 assert_eq!(try_thunk.evaluate(), Err("error"));
1364 }
1365
1366 #[test]
1370 fn test_map_failure() {
1371 let try_thunk = TryThunk::<i32, &str>::err("error").map(|x| x * 2);
1372 assert_eq!(try_thunk.evaluate(), Err("error"));
1373 }
1374
1375 #[test]
1379 fn test_map_err_success() {
1380 let try_thunk = TryThunk::<i32, &str>::pure(42).map_err(|_| "new error");
1381 assert_eq!(try_thunk.evaluate(), Ok(42));
1382 }
1383
1384 #[test]
1386 fn test_try_thunk_from_memo() {
1387 use crate::types::RcLazy;
1388 let memo = RcLazy::new(|| 42);
1389 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1390 assert_eq!(try_thunk.evaluate(), Ok(42));
1391 }
1392
1393 #[test]
1395 fn test_try_thunk_from_try_memo() {
1396 use crate::types::RcTryLazy;
1397 let memo = RcTryLazy::new(|| Ok(42));
1398 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1399 assert_eq!(try_thunk.evaluate(), Ok(42));
1400 }
1401
1402 #[test]
1406 fn test_try_thunk_from_eval() {
1407 let eval = Thunk::pure(42);
1408 let try_thunk: TryThunk<i32, ()> = TryThunk::from(eval);
1409 assert_eq!(try_thunk.evaluate(), Ok(42));
1410 }
1411
1412 #[test]
1414 fn test_defer() {
1415 let try_thunk: TryThunk<i32, ()> = TryThunk::defer(|| TryThunk::pure(42));
1416 assert_eq!(try_thunk.evaluate(), Ok(42));
1417 }
1418
1419 #[test]
1423 fn test_catch() {
1424 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error").catch(|_| TryThunk::pure(42));
1425 assert_eq!(try_thunk.evaluate(), Ok(42));
1426 }
1427
1428 #[test]
1430 fn test_try_thunk_with_err_brand() {
1431 use crate::{
1432 brands::*,
1433 functions::*,
1434 };
1435
1436 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1438 let mapped = map::<TryThunkErrAppliedBrand<()>, _, _>(|x| x * 2, try_thunk);
1439 assert_eq!(mapped.evaluate(), Ok(20));
1440
1441 let try_thunk: TryThunk<i32, ()> = pure::<TryThunkErrAppliedBrand<()>, _>(42);
1443 assert_eq!(try_thunk.evaluate(), Ok(42));
1444
1445 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1447 let bound = bind::<TryThunkErrAppliedBrand<()>, _, _>(try_thunk, |x| {
1448 pure::<TryThunkErrAppliedBrand<()>, _>(x * 2)
1449 });
1450 assert_eq!(bound.evaluate(), Ok(20));
1451
1452 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1454 let folded = fold_right::<RcFnBrand, TryThunkErrAppliedBrand<()>, _, _>(
1455 |x, acc| x + acc,
1456 5,
1457 try_thunk,
1458 );
1459 assert_eq!(folded, 15);
1460 }
1461
1462 #[test]
1464 fn test_bifunctor() {
1465 use crate::{
1466 brands::*,
1467 classes::bifunctor::*,
1468 };
1469
1470 let x: TryThunk<i32, i32> = TryThunk::pure(5);
1471 assert_eq!(bimap::<TryThunkBrand, _, _, _, _>(|e| e + 1, |s| s * 2, x).evaluate(), Ok(10));
1472
1473 let y: TryThunk<i32, i32> = TryThunk::err(5);
1474 assert_eq!(bimap::<TryThunkBrand, _, _, _, _>(|e| e + 1, |s| s * 2, y).evaluate(), Err(6));
1475 }
1476
1477 #[test]
1479 fn test_try_thunk_with_ok_brand() {
1480 use crate::{
1481 brands::*,
1482 functions::*,
1483 };
1484
1485 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1487 let mapped = map::<TryThunkOkAppliedBrand<i32>, _, _>(|x| x * 2, try_thunk);
1488 assert_eq!(mapped.evaluate(), Err(20));
1489
1490 let try_thunk: TryThunk<i32, i32> = pure::<TryThunkOkAppliedBrand<i32>, _>(42);
1492 assert_eq!(try_thunk.evaluate(), Err(42));
1493
1494 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1496 let bound = bind::<TryThunkOkAppliedBrand<i32>, _, _>(try_thunk, |x| {
1497 pure::<TryThunkOkAppliedBrand<i32>, _>(x * 2)
1498 });
1499 assert_eq!(bound.evaluate(), Err(20));
1500
1501 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1503 let folded = fold_right::<RcFnBrand, TryThunkOkAppliedBrand<i32>, _, _>(
1504 |x, acc| x + acc,
1505 5,
1506 try_thunk,
1507 );
1508 assert_eq!(folded, 15);
1509 }
1510}