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 pub struct TryThunk<'a, A, E>(
61 Box<dyn FnOnce() -> Result<A, E> + 'a>,
63 );
64
65 #[document_type_parameters(
66 "The lifetime of the computation.",
67 "The type of the success value.",
68 "The type of the error value."
69 )]
70 #[document_parameters("The `TryThunk` instance.")]
71 impl<'a, A: 'a, E: 'a> TryThunk<'a, A, E> {
72 #[document_signature]
74 #[document_parameters("The thunk to wrap.")]
76 #[document_returns("A new `TryThunk` instance.")]
78 #[document_examples]
80 pub fn new(f: impl FnOnce() -> Result<A, E> + 'a) -> Self {
88 TryThunk(Box::new(f))
89 }
90
91 #[document_signature]
93 #[document_parameters("The value to wrap.")]
95 #[document_returns("A new `TryThunk` instance containing the value.")]
97 #[document_examples]
99 pub fn pure(a: A) -> Self
107 where
108 A: 'a, {
109 TryThunk::new(move || Ok(a))
110 }
111
112 #[document_signature]
114 #[document_parameters("The thunk that returns a `TryThunk`.")]
116 #[document_returns("A new `TryThunk` instance.")]
118 #[document_examples]
120 pub fn defer(f: impl FnOnce() -> TryThunk<'a, A, E> + 'a) -> Self {
128 TryThunk::new(move || f().evaluate())
129 }
130
131 #[document_signature]
135 #[document_parameters("The value to wrap.")]
137 #[document_returns("A new `TryThunk` instance containing the value.")]
139 #[document_examples]
141 pub fn ok(a: A) -> Self
149 where
150 A: 'a, {
151 Self::pure(a)
152 }
153
154 #[document_signature]
156 #[document_parameters("The error to wrap.")]
158 #[document_returns("A new `TryThunk` instance containing the error.")]
160 #[document_examples]
162 pub fn err(e: E) -> Self
170 where
171 E: 'a, {
172 TryThunk::new(move || Err(e))
173 }
174
175 #[document_signature]
177 #[document_type_parameters("The type of the result of the new computation.")]
179 #[document_parameters("The function to apply to the result of the computation.")]
181 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
183 #[document_examples]
185 pub fn bind<B: 'a>(
193 self,
194 f: impl FnOnce(A) -> TryThunk<'a, B, E> + 'a,
195 ) -> TryThunk<'a, B, E> {
196 TryThunk::new(move || match (self.0)() {
197 Ok(a) => (f(a).0)(),
198 Err(e) => Err(e),
199 })
200 }
201
202 #[document_signature]
204 #[document_type_parameters("The type of the result of the transformation.")]
206 #[document_parameters("The function to apply to the result of the computation.")]
208 #[document_returns("A new `TryThunk` instance with the transformed result.")]
210 #[document_examples]
212 pub fn map<B: 'a>(
220 self,
221 func: impl FnOnce(A) -> B + 'a,
222 ) -> TryThunk<'a, B, E> {
223 TryThunk::new(move || (self.0)().map(func))
224 }
225
226 #[document_signature]
228 #[document_type_parameters("The type of the new error.")]
230 #[document_parameters("The function to apply to the error.")]
232 #[document_returns("A new `TryThunk` instance with the transformed error.")]
234 #[document_examples]
236 pub fn map_err<E2: 'a>(
244 self,
245 f: impl FnOnce(E) -> E2 + 'a,
246 ) -> TryThunk<'a, A, E2> {
247 TryThunk::new(move || (self.0)().map_err(f))
248 }
249
250 #[document_signature]
252 #[document_parameters("The function to apply to the error value.")]
254 #[document_returns("A new `TryThunk` that attempts to recover from failure.")]
256 #[document_examples]
258 pub fn catch(
266 self,
267 f: impl FnOnce(E) -> TryThunk<'a, A, E> + 'a,
268 ) -> Self {
269 TryThunk::new(move || match (self.0)() {
270 Ok(a) => Ok(a),
271 Err(e) => (f(e).0)(),
272 })
273 }
274
275 #[document_signature]
277 #[document_returns("The result of the computation.")]
279 #[document_examples]
281 pub fn evaluate(self) -> Result<A, E> {
289 (self.0)()
290 }
291 }
292
293 #[document_type_parameters(
294 "The lifetime of the computation.",
295 "The type of the success value.",
296 "The type of the error value.",
297 "The memoization configuration."
298 )]
299 impl<'a, A, E, Config> From<Lazy<'a, A, Config>> for TryThunk<'a, A, E>
300 where
301 A: Clone + 'a,
302 E: 'a,
303 Config: LazyConfig,
304 {
305 #[document_signature]
306 #[document_parameters("The lazy value to convert.")]
307 #[document_returns("A new `TryThunk` instance that wraps the lazy value.")]
308 #[document_examples]
309 fn from(memo: Lazy<'a, A, Config>) -> Self {
317 TryThunk::new(move || Ok(memo.evaluate().clone()))
318 }
319 }
320
321 #[document_type_parameters(
322 "The lifetime of the computation.",
323 "The type of the success value.",
324 "The type of the error value.",
325 "The memoization configuration."
326 )]
327 impl<'a, A, E, Config> From<TryLazy<'a, A, E, Config>> for TryThunk<'a, A, E>
328 where
329 A: Clone + 'a,
330 E: Clone + 'a,
331 Config: LazyConfig,
332 {
333 #[document_signature]
334 #[document_parameters("The fallible lazy value to convert.")]
335 #[document_returns("A new `TryThunk` instance that wraps the fallible lazy value.")]
336 #[document_examples]
337 fn from(memo: TryLazy<'a, A, E, Config>) -> Self {
345 TryThunk::new(move || memo.evaluate().cloned().map_err(Clone::clone))
346 }
347 }
348
349 #[document_type_parameters(
350 "The lifetime of the computation.",
351 "The type of the success value.",
352 "The type of the error value."
353 )]
354 impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E> {
355 #[document_signature]
356 #[document_parameters("The thunk to convert.")]
357 #[document_returns("A new `TryThunk` instance that wraps the thunk.")]
358 #[document_examples]
359 fn from(eval: Thunk<'a, A>) -> Self {
367 TryThunk::new(move || Ok(eval.evaluate()))
368 }
369 }
370
371 #[document_type_parameters(
372 "The lifetime of the computation.",
373 "The type of the success value.",
374 "The type of the error value."
375 )]
376 impl<'a, A, E> Deferrable<'a> for TryThunk<'a, A, E>
377 where
378 A: 'a,
379 E: 'a,
380 {
381 #[document_signature]
383 #[document_parameters("A thunk that produces the try thunk.")]
385 #[document_returns("The deferred try thunk.")]
387 #[document_examples]
389 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
402 where
403 Self: Sized, {
404 TryThunk::defer(f)
405 }
406 }
407
408 impl_kind! {
409 impl<E: 'static> for TryThunkErrAppliedBrand<E> {
410 #[document_default]
411 type Of<'a, A: 'a>: 'a = TryThunk<'a, A, E>;
412 }
413 }
414
415 #[document_type_parameters("The error type.")]
416 impl<E: 'static> Functor for TryThunkErrAppliedBrand<E> {
417 #[document_signature]
419 #[document_type_parameters(
421 "The lifetime of the computation.",
422 "The type of the value inside the `TryThunk`.",
423 "The type of the result of the transformation."
424 )]
425 #[document_parameters(
427 "The function to apply to the result of the computation.",
428 "The `TryThunk` instance."
429 )]
430 #[document_returns("A new `TryThunk` instance with the transformed result.")]
432 #[document_examples]
433 fn map<'a, A: 'a, B: 'a>(
446 func: impl Fn(A) -> B + 'a,
447 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
448 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
449 fa.map(func)
450 }
451 }
452
453 #[document_type_parameters("The error type.")]
454 impl<E: 'static> Pointed for TryThunkErrAppliedBrand<E> {
455 #[document_signature]
457 #[document_type_parameters(
459 "The lifetime of the computation.",
460 "The type of the value to wrap."
461 )]
462 #[document_parameters("The value to wrap.")]
464 #[document_returns("A new `TryThunk` instance containing the value.")]
466 #[document_examples]
468 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
480 TryThunk::pure(a)
481 }
482 }
483
484 #[document_type_parameters("The error type.")]
485 impl<E: 'static> Lift for TryThunkErrAppliedBrand<E> {
486 #[document_signature]
488 #[document_type_parameters(
490 "The lifetime of the computation.",
491 "The type of the first value.",
492 "The type of the second value.",
493 "The type of the result."
494 )]
495 #[document_parameters(
497 "The binary function to apply.",
498 "The first `TryThunk`.",
499 "The second `TryThunk`."
500 )]
501 #[document_returns(
503 "A new `TryThunk` instance containing the result of applying the function."
504 )]
505 #[document_examples]
506 fn lift2<'a, A, B, C>(
520 func: impl Fn(A, B) -> C + 'a,
521 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
522 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
523 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
524 where
525 A: Clone + 'a,
526 B: Clone + 'a,
527 C: 'a, {
528 fa.bind(move |a| fb.map(move |b| func(a, b)))
529 }
530 }
531
532 #[document_type_parameters("The error type.")]
533 impl<E: 'static> ApplyFirst for TryThunkErrAppliedBrand<E> {}
534
535 #[document_type_parameters("The error type.")]
536 impl<E: 'static> ApplySecond for TryThunkErrAppliedBrand<E> {}
537
538 #[document_type_parameters("The error type.")]
539 impl<E: 'static> Semiapplicative for TryThunkErrAppliedBrand<E> {
540 #[document_signature]
542 #[document_type_parameters(
544 "The lifetime of the computation.",
545 "The brand of the cloneable function wrapper.",
546 "The type of the input.",
547 "The type of the result."
548 )]
549 #[document_parameters(
551 "The `TryThunk` containing the function.",
552 "The `TryThunk` containing the value."
553 )]
554 #[document_returns(
556 "A new `TryThunk` instance containing the result of applying the function."
557 )]
558 #[document_examples]
559 fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
574 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
575 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
576 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
577 ff.bind(move |f| {
578 fa.map(
579 #[allow(clippy::redundant_closure)] move |a| f(a),
581 )
582 })
583 }
584 }
585
586 #[document_type_parameters("The error type.")]
587 impl<E: 'static> Semimonad for TryThunkErrAppliedBrand<E> {
588 #[document_signature]
590 #[document_type_parameters(
592 "The lifetime of the computation.",
593 "The type of the result of the first computation.",
594 "The type of the result of the new computation."
595 )]
596 #[document_parameters(
598 "The first `TryThunk`.",
599 "The function to apply to the result of the computation."
600 )]
601 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
603 #[document_examples]
604 fn bind<'a, A: 'a, B: 'a>(
619 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
620 func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
621 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
622 ma.bind(func)
623 }
624 }
625
626 #[document_type_parameters("The error type.")]
627 impl<E: 'static> MonadRec for TryThunkErrAppliedBrand<E> {
628 #[document_signature]
630 #[document_type_parameters(
632 "The lifetime of the computation.",
633 "The type of the initial value and loop state.",
634 "The type of the result."
635 )]
636 #[document_parameters("The step function.", "The initial value.")]
638 #[document_returns("The result of the computation.")]
640 #[document_examples]
642 fn tail_rec_m<'a, A: 'a, B: 'a>(
662 f: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Step<A, B>>)
663 + Clone
664 + 'a,
665 a: A,
666 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
667 TryThunk::new(move || {
668 let mut current = a;
669 loop {
670 match f(current).evaluate() {
671 Ok(Step::Loop(next)) => current = next,
672 Ok(Step::Done(res)) => break Ok(res),
673 Err(e) => break Err(e),
674 }
675 }
676 })
677 }
678 }
679
680 #[document_type_parameters("The error type.")]
681 impl<E: 'static> Foldable for TryThunkErrAppliedBrand<E> {
682 #[document_signature]
684 #[document_type_parameters(
686 "The lifetime of the computation.",
687 "The brand of the cloneable function to use.",
688 "The type of the elements in the structure.",
689 "The type of the accumulator."
690 )]
691 #[document_parameters(
693 "The function to apply to each element and the accumulator.",
694 "The initial value of the accumulator.",
695 "The `TryThunk` to fold."
696 )]
697 #[document_returns("The final accumulator value.")]
699 #[document_examples]
700 fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
714 func: impl Fn(A, B) -> B + 'a,
715 initial: B,
716 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
717 ) -> B
718 where
719 FnBrand: CloneableFn + 'a, {
720 match fa.evaluate() {
721 Ok(a) => func(a, initial),
722 Err(_) => initial,
723 }
724 }
725
726 #[document_signature]
728 #[document_type_parameters(
730 "The lifetime of the computation.",
731 "The brand of the cloneable function to use.",
732 "The type of the elements in the structure.",
733 "The type of the accumulator."
734 )]
735 #[document_parameters(
737 "The function to apply to the accumulator and each element.",
738 "The initial value of the accumulator.",
739 "The `TryThunk` to fold."
740 )]
741 #[document_returns("The final accumulator value.")]
743 #[document_examples]
744 fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
758 func: impl Fn(B, A) -> B + 'a,
759 initial: B,
760 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
761 ) -> B
762 where
763 FnBrand: CloneableFn + 'a, {
764 match fa.evaluate() {
765 Ok(a) => func(initial, a),
766 Err(_) => initial,
767 }
768 }
769
770 #[document_signature]
772 #[document_type_parameters(
774 "The lifetime of the computation.",
775 "The brand of the cloneable function to use.",
776 "The type of the elements in the structure.",
777 "The type of the monoid."
778 )]
779 #[document_parameters("The mapping function.", "The Thunk to fold.")]
781 #[document_returns("The monoid value.")]
783 #[document_examples]
785 fn fold_map<'a, FnBrand, A: 'a + Clone, M>(
799 func: impl Fn(A) -> M + 'a,
800 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
801 ) -> M
802 where
803 M: Monoid + 'a,
804 FnBrand: CloneableFn + 'a, {
805 match fa.evaluate() {
806 Ok(a) => func(a),
807 Err(_) => M::empty(),
808 }
809 }
810 }
811
812 #[document_type_parameters(
813 "The lifetime of the computation.",
814 "The success value type.",
815 "The error value type."
816 )]
817 impl<'a, A: Semigroup + 'a, E: 'a> Semigroup for TryThunk<'a, A, E> {
818 #[document_signature]
820 #[document_parameters("The first `TryThunk`.", "The second `TryThunk`.")]
822 #[document_returns("A new `TryThunk` containing the combined result.")]
824 #[document_examples]
826 fn append(
841 a: Self,
842 b: Self,
843 ) -> Self {
844 TryThunk::new(move || match (a.evaluate(), b.evaluate()) {
845 (Ok(a_val), Ok(b_val)) => Ok(Semigroup::append(a_val, b_val)),
846 (Err(e), _) => Err(e),
847 (_, Err(e)) => Err(e),
848 })
849 }
850 }
851
852 #[document_type_parameters(
853 "The lifetime of the computation.",
854 "The success value type.",
855 "The error value type."
856 )]
857 impl<'a, A: Monoid + 'a, E: 'a> Monoid for TryThunk<'a, A, E> {
858 #[document_signature]
860 #[document_returns("A `TryThunk` producing the identity value of `A`.")]
862 #[document_examples]
864 fn empty() -> Self {
875 TryThunk::new(|| Ok(Monoid::empty()))
876 }
877 }
878
879 impl_kind! {
880 for TryThunkBrand {
887 type Of<'a, E: 'a, A: 'a>: 'a = TryThunk<'a, A, E>;
888 }
889 }
890
891 impl Bifunctor for TryThunkBrand {
892 #[document_signature]
896 #[document_type_parameters(
898 "The lifetime of the values.",
899 "The type of the error value.",
900 "The type of the mapped error value.",
901 "The type of the success value.",
902 "The type of the mapped success value."
903 )]
904 #[document_parameters(
906 "The function to apply to the error.",
907 "The function to apply to the success.",
908 "The `TryThunk` to map over."
909 )]
910 #[document_returns("A new `TryThunk` containing the mapped values.")]
912 #[document_examples]
913 fn bimap<'a, A: 'a, B: 'a, C: 'a, D: 'a>(
929 f: impl Fn(A) -> B + 'a,
930 g: impl Fn(C) -> D + 'a,
931 p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
932 ) -> Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, D>) {
933 TryThunk::new(move || match p.evaluate() {
934 Ok(c) => Ok(g(c)),
935 Err(a) => Err(f(a)),
936 })
937 }
938 }
939
940 impl_kind! {
941 impl<A: 'static> for TryThunkOkAppliedBrand<A> {
942 #[document_default]
943 type Of<'a, E: 'a>: 'a = TryThunk<'a, A, E>;
944 }
945 }
946
947 #[document_type_parameters("The success type.")]
948 impl<A: 'static> Functor for TryThunkOkAppliedBrand<A> {
949 #[document_signature]
951 #[document_type_parameters(
953 "The lifetime of the computation.",
954 "The type of the error value inside the `TryThunk`.",
955 "The type of the result of the transformation."
956 )]
957 #[document_parameters("The function to apply to the error.", "The `TryThunk` instance.")]
959 #[document_returns("A new `TryThunk` instance with the transformed error.")]
961 #[document_examples]
963 fn map<'a, E: 'a, E2: 'a>(
976 func: impl Fn(E) -> E2 + 'a,
977 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
978 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
979 fa.map_err(func)
980 }
981 }
982
983 #[document_type_parameters("The success type.")]
984 impl<A: 'static> Pointed for TryThunkOkAppliedBrand<A> {
985 #[document_signature]
987 #[document_type_parameters(
989 "The lifetime of the computation.",
990 "The type of the value to wrap."
991 )]
992 #[document_parameters("The value to wrap.")]
994 #[document_returns("A new `TryThunk` instance containing the value as an error.")]
996 #[document_examples]
998 fn pure<'a, E: 'a>(e: E) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>) {
1010 TryThunk::err(e)
1011 }
1012 }
1013
1014 #[document_type_parameters("The success type.")]
1015 impl<A: 'static> Lift for TryThunkOkAppliedBrand<A> {
1016 #[document_signature]
1018 #[document_type_parameters(
1020 "The lifetime of the computation.",
1021 "The type of the first error value.",
1022 "The type of the second error value.",
1023 "The type of the result error value."
1024 )]
1025 #[document_parameters(
1027 "The binary function to apply to the errors.",
1028 "The first `TryThunk`.",
1029 "The second `TryThunk`."
1030 )]
1031 #[document_returns(
1033 "A new `TryThunk` instance containing the result of applying the function to the errors."
1034 )]
1035 #[document_examples]
1036 fn lift2<'a, E1, E2, E3>(
1050 func: impl Fn(E1, E2) -> E3 + 'a,
1051 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1052 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>),
1053 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E3>)
1054 where
1055 E1: Clone + 'a,
1056 E2: Clone + 'a,
1057 E3: 'a, {
1058 TryThunk::new(move || match (fa.evaluate(), fb.evaluate()) {
1059 (Err(e1), Err(e2)) => Err(func(e1, e2)),
1060 (Ok(a), _) => Ok(a),
1061 (_, Ok(a)) => Ok(a),
1062 })
1063 }
1064 }
1065
1066 #[document_type_parameters("The success type.")]
1067 impl<A: 'static> ApplyFirst for TryThunkOkAppliedBrand<A> {}
1068
1069 #[document_type_parameters("The success type.")]
1070 impl<A: 'static> ApplySecond for TryThunkOkAppliedBrand<A> {}
1071
1072 #[document_type_parameters("The success type.")]
1073 impl<A: 'static> Semiapplicative for TryThunkOkAppliedBrand<A> {
1074 #[document_signature]
1076 #[document_type_parameters(
1078 "The lifetime of the computation.",
1079 "The brand of the cloneable function wrapper.",
1080 "The type of the input error.",
1081 "The type of the result error."
1082 )]
1083 #[document_parameters(
1085 "The `TryThunk` containing the function (in Err).",
1086 "The `TryThunk` containing the value (in Err)."
1087 )]
1088 #[document_returns(
1090 "A new `TryThunk` instance containing the result of applying the function."
1091 )]
1092 #[document_examples]
1093 fn apply<'a, FnBrand: 'a + CloneableFn, E1: 'a + Clone, E2: 'a>(
1108 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, E1, E2>>),
1109 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1110 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1111 TryThunk::new(move || match (ff.evaluate(), fa.evaluate()) {
1112 (Err(f), Err(e)) => Err(f(e)),
1113 (Ok(a), _) => Ok(a),
1114 (_, Ok(a)) => Ok(a),
1115 })
1116 }
1117 }
1118
1119 #[document_type_parameters("The success type.")]
1120 impl<A: 'static> Semimonad for TryThunkOkAppliedBrand<A> {
1121 #[document_signature]
1123 #[document_type_parameters(
1125 "The lifetime of the computation.",
1126 "The type of the result of the first computation (error).",
1127 "The type of the result of the new computation (error)."
1128 )]
1129 #[document_parameters(
1131 "The first `TryThunk`.",
1132 "The function to apply to the error result of the computation."
1133 )]
1134 #[document_returns("A new `TryThunk` instance representing the chained computation.")]
1136 #[document_examples]
1137 fn bind<'a, E1: 'a, E2: 'a>(
1152 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1153 func: impl Fn(E1) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) + 'a,
1154 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1155 TryThunk::new(move || match ma.evaluate() {
1156 Ok(a) => Ok(a),
1157 Err(e) => func(e).evaluate(),
1158 })
1159 }
1160 }
1161
1162 #[document_type_parameters("The success type.")]
1163 impl<A: 'static> Foldable for TryThunkOkAppliedBrand<A> {
1164 #[document_signature]
1166 #[document_type_parameters(
1168 "The lifetime of the computation.",
1169 "The brand of the cloneable function to use.",
1170 "The type of the elements in the structure.",
1171 "The type of the accumulator."
1172 )]
1173 #[document_parameters(
1175 "The function to apply to each element and the accumulator.",
1176 "The initial value of the accumulator.",
1177 "The `TryThunk` to fold."
1178 )]
1179 #[document_returns("The final accumulator value.")]
1181 #[document_examples]
1182 fn fold_right<'a, FnBrand, E: 'a + Clone, B: 'a>(
1196 func: impl Fn(E, B) -> B + 'a,
1197 initial: B,
1198 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1199 ) -> B
1200 where
1201 FnBrand: CloneableFn + 'a, {
1202 match fa.evaluate() {
1203 Err(e) => func(e, initial),
1204 Ok(_) => initial,
1205 }
1206 }
1207
1208 #[document_signature]
1210 #[document_type_parameters(
1212 "The lifetime of the computation.",
1213 "The brand of the cloneable function to use.",
1214 "The type of the elements in the structure.",
1215 "The type of the accumulator."
1216 )]
1217 #[document_parameters(
1219 "The function to apply to the accumulator and each element.",
1220 "The initial value of the accumulator.",
1221 "The `TryThunk` to fold."
1222 )]
1223 #[document_returns("The final accumulator value.")]
1225 #[document_examples]
1226 fn fold_left<'a, FnBrand, E: 'a + Clone, B: 'a>(
1240 func: impl Fn(B, E) -> B + 'a,
1241 initial: B,
1242 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1243 ) -> B
1244 where
1245 FnBrand: CloneableFn + 'a, {
1246 match fa.evaluate() {
1247 Err(e) => func(initial, e),
1248 Ok(_) => initial,
1249 }
1250 }
1251
1252 #[document_signature]
1254 #[document_type_parameters(
1256 "The lifetime of the computation.",
1257 "The brand of the cloneable function to use.",
1258 "The type of the elements in the structure.",
1259 "The type of the monoid."
1260 )]
1261 #[document_parameters("The mapping function.", "The Thunk to fold.")]
1263 #[document_returns("The monoid value.")]
1265 #[document_examples]
1267 fn fold_map<'a, FnBrand, E: 'a + Clone, M>(
1281 func: impl Fn(E) -> M + 'a,
1282 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1283 ) -> M
1284 where
1285 M: Monoid + 'a,
1286 FnBrand: CloneableFn + 'a, {
1287 match fa.evaluate() {
1288 Err(e) => func(e),
1289 Ok(_) => M::empty(),
1290 }
1291 }
1292 }
1293}
1294pub use inner::*;
1295
1296#[cfg(test)]
1297mod tests {
1298 use {
1299 super::*,
1300 crate::types::Thunk,
1301 };
1302
1303 #[test]
1307 fn test_success() {
1308 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
1309 assert_eq!(try_thunk.evaluate(), Ok(42));
1310 }
1311
1312 #[test]
1316 fn test_failure() {
1317 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error");
1318 assert_eq!(try_thunk.evaluate(), Err("error"));
1319 }
1320
1321 #[test]
1325 fn test_map() {
1326 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).map(|x| x * 2);
1327 assert_eq!(try_thunk.evaluate(), Ok(42));
1328 }
1329
1330 #[test]
1334 fn test_map_err() {
1335 let try_thunk: TryThunk<i32, i32> = TryThunk::err(21).map_err(|x| x * 2);
1336 assert_eq!(try_thunk.evaluate(), Err(42));
1337 }
1338
1339 #[test]
1343 fn test_bind() {
1344 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).bind(|x| TryThunk::pure(x * 2));
1345 assert_eq!(try_thunk.evaluate(), Ok(42));
1346 }
1347
1348 #[test]
1352 fn test_borrowing() {
1353 let x = 42;
1354 let try_thunk: TryThunk<&i32, ()> = TryThunk::new(|| Ok(&x));
1355 assert_eq!(try_thunk.evaluate(), Ok(&42));
1356 }
1357
1358 #[test]
1362 fn test_bind_failure() {
1363 let try_thunk = TryThunk::<i32, &str>::err("error").bind(|x| TryThunk::pure(x * 2));
1364 assert_eq!(try_thunk.evaluate(), Err("error"));
1365 }
1366
1367 #[test]
1371 fn test_map_failure() {
1372 let try_thunk = TryThunk::<i32, &str>::err("error").map(|x| x * 2);
1373 assert_eq!(try_thunk.evaluate(), Err("error"));
1374 }
1375
1376 #[test]
1380 fn test_map_err_success() {
1381 let try_thunk = TryThunk::<i32, &str>::pure(42).map_err(|_| "new error");
1382 assert_eq!(try_thunk.evaluate(), Ok(42));
1383 }
1384
1385 #[test]
1387 fn test_try_thunk_from_memo() {
1388 use crate::types::RcLazy;
1389 let memo = RcLazy::new(|| 42);
1390 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1391 assert_eq!(try_thunk.evaluate(), Ok(42));
1392 }
1393
1394 #[test]
1396 fn test_try_thunk_from_try_memo() {
1397 use crate::types::RcTryLazy;
1398 let memo = RcTryLazy::new(|| Ok(42));
1399 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1400 assert_eq!(try_thunk.evaluate(), Ok(42));
1401 }
1402
1403 #[test]
1407 fn test_try_thunk_from_eval() {
1408 let eval = Thunk::pure(42);
1409 let try_thunk: TryThunk<i32, ()> = TryThunk::from(eval);
1410 assert_eq!(try_thunk.evaluate(), Ok(42));
1411 }
1412
1413 #[test]
1415 fn test_defer() {
1416 let try_thunk: TryThunk<i32, ()> = TryThunk::defer(|| TryThunk::pure(42));
1417 assert_eq!(try_thunk.evaluate(), Ok(42));
1418 }
1419
1420 #[test]
1424 fn test_catch() {
1425 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error").catch(|_| TryThunk::pure(42));
1426 assert_eq!(try_thunk.evaluate(), Ok(42));
1427 }
1428
1429 #[test]
1431 fn test_try_thunk_with_err_brand() {
1432 use crate::{
1433 brands::*,
1434 functions::*,
1435 };
1436
1437 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1439 let mapped = map::<TryThunkErrAppliedBrand<()>, _, _>(|x| x * 2, try_thunk);
1440 assert_eq!(mapped.evaluate(), Ok(20));
1441
1442 let try_thunk: TryThunk<i32, ()> = pure::<TryThunkErrAppliedBrand<()>, _>(42);
1444 assert_eq!(try_thunk.evaluate(), Ok(42));
1445
1446 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1448 let bound = bind::<TryThunkErrAppliedBrand<()>, _, _>(try_thunk, |x| {
1449 pure::<TryThunkErrAppliedBrand<()>, _>(x * 2)
1450 });
1451 assert_eq!(bound.evaluate(), Ok(20));
1452
1453 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1455 let folded = fold_right::<RcFnBrand, TryThunkErrAppliedBrand<()>, _, _>(
1456 |x, acc| x + acc,
1457 5,
1458 try_thunk,
1459 );
1460 assert_eq!(folded, 15);
1461 }
1462
1463 #[test]
1465 fn test_bifunctor() {
1466 use crate::{
1467 brands::*,
1468 classes::bifunctor::*,
1469 };
1470
1471 let x: TryThunk<i32, i32> = TryThunk::pure(5);
1472 assert_eq!(bimap::<TryThunkBrand, _, _, _, _>(|e| e + 1, |s| s * 2, x).evaluate(), Ok(10));
1473
1474 let y: TryThunk<i32, i32> = TryThunk::err(5);
1475 assert_eq!(bimap::<TryThunkBrand, _, _, _, _>(|e| e + 1, |s| s * 2, y).evaluate(), Err(6));
1476 }
1477
1478 #[test]
1480 fn test_try_thunk_with_ok_brand() {
1481 use crate::{
1482 brands::*,
1483 functions::*,
1484 };
1485
1486 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1488 let mapped = map::<TryThunkOkAppliedBrand<i32>, _, _>(|x| x * 2, try_thunk);
1489 assert_eq!(mapped.evaluate(), Err(20));
1490
1491 let try_thunk: TryThunk<i32, i32> = pure::<TryThunkOkAppliedBrand<i32>, _>(42);
1493 assert_eq!(try_thunk.evaluate(), Err(42));
1494
1495 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1497 let bound = bind::<TryThunkOkAppliedBrand<i32>, _, _>(try_thunk, |x| {
1498 pure::<TryThunkOkAppliedBrand<i32>, _>(x * 2)
1499 });
1500 assert_eq!(bound.evaluate(), Err(20));
1501
1502 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1504 let folded = fold_right::<RcFnBrand, TryThunkOkAppliedBrand<i32>, _, _>(
1505 |x, acc| x + acc,
1506 5,
1507 try_thunk,
1508 );
1509 assert_eq!(folded, 15);
1510 }
1511}