1use crate::{
6 Apply,
7 brands::{TryThunkBrand, TryThunkWithErrBrand, TryThunkWithOkBrand},
8 classes::{
9 ApplyFirst, ApplySecond, Bifunctor, CloneableFn, Deferrable, Foldable, Functor, Lift,
10 MonadRec, Monoid, Pointed, Semiapplicative, Semigroup, Semimonad,
11 },
12 impl_kind,
13 kinds::*,
14 types::{Lazy, LazyConfig, Step, Thunk, TryLazy},
15};
16use fp_macros::{doc_params, doc_type_params, hm_signature};
17
18pub struct TryThunk<'a, A, E>(Box<dyn FnOnce() -> Result<A, E> + 'a>);
47
48impl<'a, A: 'a, E: 'a> TryThunk<'a, A, E> {
49 #[hm_signature]
54 #[doc_type_params("The type of the thunk.")]
58 #[doc_params("The thunk to wrap.")]
62 pub fn new<F>(f: F) -> Self
76 where
77 F: FnOnce() -> Result<A, E> + 'a,
78 {
79 TryThunk(Box::new(f))
80 }
81
82 #[hm_signature]
87 #[doc_params("The value to wrap.")]
91 pub fn pure(a: A) -> Self
105 where
106 A: 'a,
107 {
108 TryThunk::new(move || Ok(a))
109 }
110
111 #[hm_signature]
116 #[doc_type_params("The type of the thunk.")]
120 #[doc_params("The thunk that returns a `TryThunk`.")]
124 pub fn defer<F>(f: F) -> Self
138 where
139 F: FnOnce() -> TryThunk<'a, A, E> + 'a,
140 {
141 TryThunk::new(move || f().evaluate())
142 }
143
144 #[hm_signature]
151 #[doc_params("The value to wrap.")]
155 pub fn ok(a: A) -> Self
169 where
170 A: 'a,
171 {
172 Self::pure(a)
173 }
174
175 #[hm_signature]
180 #[doc_params("The error to wrap.")]
184 pub fn err(e: E) -> Self
198 where
199 E: 'a,
200 {
201 TryThunk::new(move || Err(e))
202 }
203
204 #[hm_signature]
209 #[doc_type_params(
213 "The type of the result of the new computation.",
214 "The type of the function to apply."
215 )]
216 #[doc_params("The function to apply to the result of the computation.")]
220 pub fn bind<B: 'a, F>(
234 self,
235 f: F,
236 ) -> TryThunk<'a, B, E>
237 where
238 F: FnOnce(A) -> TryThunk<'a, B, E> + 'a,
239 {
240 TryThunk::new(move || match (self.0)() {
241 Ok(a) => (f(a).0)(),
242 Err(e) => Err(e),
243 })
244 }
245
246 #[hm_signature]
251 #[doc_type_params(
255 "The type of the result of the transformation.",
256 ("F", "The type of the transformation function.")
257 )]
258 #[doc_params("The function to apply to the result of the computation.")]
262 pub fn map<B: 'a, Func>(
276 self,
277 func: Func,
278 ) -> TryThunk<'a, B, E>
279 where
280 Func: FnOnce(A) -> B + 'a,
281 {
282 TryThunk::new(move || (self.0)().map(func))
283 }
284
285 #[hm_signature]
290 #[doc_type_params("The type of the new error.", "The type of the transformation function.")]
294 #[doc_params("The function to apply to the error.")]
298 pub fn map_err<E2: 'a, F>(
312 self,
313 f: F,
314 ) -> TryThunk<'a, A, E2>
315 where
316 F: FnOnce(E) -> E2 + 'a,
317 {
318 TryThunk::new(move || (self.0)().map_err(f))
319 }
320
321 #[hm_signature]
326 #[doc_type_params("The type of the recovery function.")]
330 #[doc_params("The function to apply to the error value.")]
334 pub fn catch<F>(
349 self,
350 f: F,
351 ) -> Self
352 where
353 F: FnOnce(E) -> TryThunk<'a, A, E> + 'a,
354 {
355 TryThunk::new(move || match (self.0)() {
356 Ok(a) => Ok(a),
357 Err(e) => (f(e).0)(),
358 })
359 }
360
361 #[hm_signature]
366 pub fn evaluate(self) -> Result<A, E> {
380 (self.0)()
381 }
382}
383
384impl<'a, A, E, Config> From<Lazy<'a, A, Config>> for TryThunk<'a, A, E>
385where
386 A: Clone + 'a,
387 E: 'a,
388 Config: LazyConfig,
389{
390 fn from(memo: Lazy<'a, A, Config>) -> Self {
391 TryThunk::new(move || Ok(memo.evaluate().clone()))
392 }
393}
394
395impl<'a, A, E, Config> From<TryLazy<'a, A, E, Config>> for TryThunk<'a, A, E>
396where
397 A: Clone + 'a,
398 E: Clone + 'a,
399 Config: LazyConfig,
400{
401 fn from(memo: TryLazy<'a, A, E, Config>) -> Self {
402 TryThunk::new(move || memo.evaluate().cloned().map_err(Clone::clone))
403 }
404}
405
406impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E> {
407 fn from(eval: Thunk<'a, A>) -> Self {
408 TryThunk::new(move || Ok(eval.evaluate()))
409 }
410}
411
412impl<'a, A, E> Deferrable<'a> for TryThunk<'a, A, E>
413where
414 A: 'a,
415 E: 'a,
416{
417 #[hm_signature(Deferrable)]
422 #[doc_type_params("The type of the thunk.")]
426 #[doc_params("A thunk that produces the try thunk.")]
430 fn defer<F>(f: F) -> Self
444 where
445 F: FnOnce() -> Self + 'a,
446 Self: Sized,
447 {
448 TryThunk::defer(f)
449 }
450}
451
452impl_kind! {
453 impl<E: 'static> for TryThunkWithErrBrand<E> {
454 type Of<'a, A: 'a>: 'a = TryThunk<'a, A, E>;
455 }
456}
457
458impl<E: 'static> Functor for TryThunkWithErrBrand<E> {
459 #[hm_signature(Functor)]
464 #[doc_type_params(
468 "The lifetime of the computation.",
469 "The type of the value inside the `TryThunk`.",
470 "The type of the result of the transformation.",
471 "The type of the transformation function."
472 )]
473 #[doc_params(
477 "The function to apply to the result of the computation.",
478 "The `TryThunk` instance."
479 )]
480 fn map<'a, A: 'a, B: 'a, Func>(
495 func: Func,
496 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
497 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
498 where
499 Func: Fn(A) -> B + 'a,
500 {
501 fa.map(func)
502 }
503}
504
505impl<E: 'static> Pointed for TryThunkWithErrBrand<E> {
506 #[hm_signature(Pointed)]
511 #[doc_type_params("The lifetime of the computation.", "The type of the value to wrap.")]
515 #[doc_params("The value to wrap.")]
519 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
533 TryThunk::pure(a)
534 }
535}
536
537impl<E: 'static> Lift for TryThunkWithErrBrand<E> {
538 #[hm_signature(Lift)]
543 #[doc_type_params(
547 "The lifetime of the computation.",
548 "The type of the first value.",
549 "The type of the second value.",
550 "The type of the result.",
551 "The type of the binary function."
552 )]
553 #[doc_params(
557 "The binary function to apply.",
558 "The first `TryThunk`.",
559 "The second `TryThunk`."
560 )]
561 fn lift2<'a, A, B, C, Func>(
577 func: Func,
578 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
579 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
580 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
581 where
582 Func: Fn(A, B) -> C + 'a,
583 A: Clone + 'a,
584 B: Clone + 'a,
585 C: 'a,
586 {
587 fa.bind(move |a| fb.map(move |b| func(a, b)))
588 }
589}
590
591impl<E: 'static> ApplyFirst for TryThunkWithErrBrand<E> {}
592impl<E: 'static> ApplySecond for TryThunkWithErrBrand<E> {}
593
594impl<E: 'static> Semiapplicative for TryThunkWithErrBrand<E> {
595 #[hm_signature(Semiapplicative)]
600 #[doc_type_params(
604 "The lifetime of the computation.",
605 "The brand of the cloneable function wrapper.",
606 "The type of the input.",
607 "The type of the result."
608 )]
609 #[doc_params("The `TryThunk` containing the function.", "The `TryThunk` containing the value.")]
613 fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
629 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
630 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
631 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
632 ff.bind(move |f| {
633 fa.map(
634 #[allow(clippy::redundant_closure)]
635 move |a| f(a),
636 )
637 })
638 }
639}
640
641impl<E: 'static> Semimonad for TryThunkWithErrBrand<E> {
642 #[hm_signature(Semimonad)]
647 #[doc_type_params(
651 "The lifetime of the computation.",
652 "The type of the result of the first computation.",
653 "The type of the result of the new computation.",
654 "The type of the function to apply."
655 )]
656 #[doc_params(
660 "The first `TryThunk`.",
661 "The function to apply to the result of the computation."
662 )]
663 fn bind<'a, A: 'a, B: 'a, Func>(
678 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
679 func: Func,
680 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
681 where
682 Func: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
683 {
684 ma.bind(func)
685 }
686}
687
688impl<E: 'static> MonadRec for TryThunkWithErrBrand<E> {
689 #[hm_signature(MonadRec)]
694 #[doc_type_params(
698 "The lifetime of the computation.",
699 "The type of the initial value and loop state.",
700 "The type of the result.",
701 "The type of the step function."
702 )]
703 #[doc_params("The step function.", "The initial value.")]
707 fn tail_rec_m<'a, A: 'a, B: 'a, F>(
724 f: F,
725 a: A,
726 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
727 where
728 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Step<A, B>>)
729 + Clone
730 + 'a,
731 {
732 TryThunk::new(move || {
733 let mut current = a;
734 loop {
735 match f(current).evaluate() {
736 Ok(Step::Loop(next)) => current = next,
737 Ok(Step::Done(res)) => break Ok(res),
738 Err(e) => break Err(e),
739 }
740 }
741 })
742 }
743}
744
745impl<E: 'static> Foldable for TryThunkWithErrBrand<E> {
746 #[hm_signature(Foldable)]
751 #[doc_type_params(
755 "The lifetime of the computation.",
756 "The brand of the cloneable function to use.",
757 "The type of the elements in the structure.",
758 "The type of the accumulator.",
759 "The type of the folding function."
760 )]
761 #[doc_params(
765 "The function to apply to each element and the accumulator.",
766 "The initial value of the accumulator.",
767 "The `TryThunk` to fold."
768 )]
769 fn fold_right<'a, FnBrand, A: 'a, B: 'a, Func>(
784 func: Func,
785 initial: B,
786 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
787 ) -> B
788 where
789 Func: Fn(A, B) -> B + 'a,
790 FnBrand: CloneableFn + 'a,
791 {
792 match fa.evaluate() {
793 Ok(a) => func(a, initial),
794 Err(_) => initial,
795 }
796 }
797
798 #[hm_signature(Foldable)]
803 #[doc_type_params(
807 "The lifetime of the computation.",
808 "The brand of the cloneable function to use.",
809 "The type of the elements in the structure.",
810 "The type of the accumulator.",
811 "The type of the folding function."
812 )]
813 #[doc_params(
817 "The function to apply to the accumulator and each element.",
818 "The initial value of the accumulator.",
819 "The `TryThunk` to fold."
820 )]
821 fn fold_left<'a, FnBrand, A: 'a, B: 'a, Func>(
836 func: Func,
837 initial: B,
838 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
839 ) -> B
840 where
841 Func: Fn(B, A) -> B + 'a,
842 FnBrand: CloneableFn + 'a,
843 {
844 match fa.evaluate() {
845 Ok(a) => func(initial, a),
846 Err(_) => initial,
847 }
848 }
849
850 #[hm_signature(Foldable)]
855 #[doc_type_params(
859 "The lifetime of the computation.",
860 "The brand of the cloneable function to use.",
861 "The type of the elements in the structure.",
862 "The type of the monoid.",
863 "The type of the mapping function."
864 )]
865 #[doc_params("The mapping function.", "The Thunk to fold.")]
869 fn fold_map<'a, FnBrand, A: 'a, M, Func>(
884 func: Func,
885 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
886 ) -> M
887 where
888 M: Monoid + 'a,
889 Func: Fn(A) -> M + 'a,
890 FnBrand: CloneableFn + 'a,
891 {
892 match fa.evaluate() {
893 Ok(a) => func(a),
894 Err(_) => M::empty(),
895 }
896 }
897}
898
899impl<'a, A: Semigroup + 'a, E: 'a> Semigroup for TryThunk<'a, A, E> {
900 #[hm_signature(Semigroup)]
905 #[doc_params("The first `TryThunk`.", "The second `TryThunk`.")]
909 fn append(
925 a: Self,
926 b: Self,
927 ) -> Self {
928 TryThunk::new(move || match (a.evaluate(), b.evaluate()) {
929 (Ok(a_val), Ok(b_val)) => Ok(Semigroup::append(a_val, b_val)),
930 (Err(e), _) => Err(e),
931 (_, Err(e)) => Err(e),
932 })
933 }
934}
935
936impl<'a, A: Monoid + 'a, E: 'a> Monoid for TryThunk<'a, A, E> {
937 #[hm_signature(Monoid)]
942 fn empty() -> Self {
956 TryThunk::new(|| Ok(Monoid::empty()))
957 }
958}
959
960impl_kind! {
961 for TryThunkBrand {
962 type Of<'a, E: 'a, A: 'a>: 'a = TryThunk<'a, A, E>;
963 }
964}
965
966impl Bifunctor for TryThunkBrand {
967 #[hm_signature(Bifunctor)]
974 #[doc_type_params(
978 "The lifetime of the values.",
979 "The type of the error value.",
980 "The type of the mapped error value.",
981 "The type of the success value.",
982 "The type of the mapped success value.",
983 "The type of the function to apply to the error.",
984 "The type of the function to apply to the success."
985 )]
986 #[doc_params(
990 "The function to apply to the error.",
991 "The function to apply to the success.",
992 "The `TryThunk` to map over."
993 )]
994 fn bimap<'a, A: 'a, B: 'a, C: 'a, D: 'a, F, G>(
1011 f: F,
1012 g: G,
1013 p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
1014 ) -> Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, D>)
1015 where
1016 F: Fn(A) -> B + 'a,
1017 G: Fn(C) -> D + 'a,
1018 {
1019 TryThunk::new(move || match p.evaluate() {
1020 Ok(c) => Ok(g(c)),
1021 Err(a) => Err(f(a)),
1022 })
1023 }
1024}
1025
1026impl_kind! {
1027 impl<A: 'static> for TryThunkWithOkBrand<A> {
1028 type Of<'a, E: 'a>: 'a = TryThunk<'a, A, E>;
1029 }
1030}
1031
1032impl<A: 'static> Functor for TryThunkWithOkBrand<A> {
1033 #[hm_signature(Functor)]
1038 #[doc_type_params(
1042 "The lifetime of the computation.",
1043 "The type of the error value inside the `TryThunk`.",
1044 "The type of the result of the transformation.",
1045 "The type of the transformation function."
1046 )]
1047 #[doc_params("The function to apply to the error.", "The `TryThunk` instance.")]
1051 fn map<'a, E: 'a, E2: 'a, Func>(
1066 func: Func,
1067 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1068 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>)
1069 where
1070 Func: Fn(E) -> E2 + 'a,
1071 {
1072 fa.map_err(func)
1073 }
1074}
1075
1076impl<A: 'static> Pointed for TryThunkWithOkBrand<A> {
1077 #[hm_signature(Pointed)]
1082 #[doc_type_params("The lifetime of the computation.", "The type of the value to wrap.")]
1086 #[doc_params("The value to wrap.")]
1090 fn pure<'a, E: 'a>(e: E) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>) {
1104 TryThunk::err(e)
1105 }
1106}
1107
1108impl<A: 'static> Lift for TryThunkWithOkBrand<A> {
1109 #[hm_signature(Lift)]
1114 #[doc_type_params(
1118 "The lifetime of the computation.",
1119 "The type of the first error value.",
1120 "The type of the second error value.",
1121 "The type of the result error value.",
1122 "The type of the binary function."
1123 )]
1124 #[doc_params(
1128 "The binary function to apply to the errors.",
1129 "The first `TryThunk`.",
1130 "The second `TryThunk`."
1131 )]
1132 fn lift2<'a, E1, E2, E3, Func>(
1148 func: Func,
1149 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1150 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>),
1151 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E3>)
1152 where
1153 Func: Fn(E1, E2) -> E3 + 'a,
1154 E1: Clone + 'a,
1155 E2: Clone + 'a,
1156 E3: 'a,
1157 {
1158 TryThunk::new(move || match (fa.evaluate(), fb.evaluate()) {
1159 (Err(e1), Err(e2)) => Err(func(e1, e2)),
1160 (Ok(a), _) => Ok(a),
1161 (_, Ok(a)) => Ok(a),
1162 })
1163 }
1164}
1165
1166impl<A: 'static> ApplyFirst for TryThunkWithOkBrand<A> {}
1167impl<A: 'static> ApplySecond for TryThunkWithOkBrand<A> {}
1168
1169impl<A: 'static> Semiapplicative for TryThunkWithOkBrand<A> {
1170 #[hm_signature(Semiapplicative)]
1175 #[doc_type_params(
1179 "The lifetime of the computation.",
1180 "The brand of the cloneable function wrapper.",
1181 "The type of the input error.",
1182 "The type of the result error."
1183 )]
1184 #[doc_params(
1188 "The `TryThunk` containing the function (in Err).",
1189 "The `TryThunk` containing the value (in Err)."
1190 )]
1191 fn apply<'a, FnBrand: 'a + CloneableFn, E1: 'a + Clone, E2: 'a>(
1207 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, E1, E2>>),
1208 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1209 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1210 TryThunk::new(move || match (ff.evaluate(), fa.evaluate()) {
1211 (Err(f), Err(e)) => Err(f(e)),
1212 (Ok(a), _) => Ok(a),
1213 (_, Ok(a)) => Ok(a),
1214 })
1215 }
1216}
1217
1218impl<A: 'static> Semimonad for TryThunkWithOkBrand<A> {
1219 #[hm_signature(Semimonad)]
1224 #[doc_type_params(
1228 "The lifetime of the computation.",
1229 "The type of the result of the first computation (error).",
1230 "The type of the result of the new computation (error).",
1231 "The type of the function to apply."
1232 )]
1233 #[doc_params(
1237 "The first `TryThunk`.",
1238 "The function to apply to the error result of the computation."
1239 )]
1240 fn bind<'a, E1: 'a, E2: 'a, Func>(
1255 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1256 func: Func,
1257 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>)
1258 where
1259 Func: Fn(E1) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) + 'a,
1260 {
1261 TryThunk::new(move || match ma.evaluate() {
1262 Ok(a) => Ok(a),
1263 Err(e) => func(e).evaluate(),
1264 })
1265 }
1266}
1267
1268impl<A: 'static> Foldable for TryThunkWithOkBrand<A> {
1269 #[hm_signature(Foldable)]
1274 #[doc_type_params(
1278 "The lifetime of the computation.",
1279 "The brand of the cloneable function to use.",
1280 "The type of the elements in the structure.",
1281 "The type of the accumulator.",
1282 "The type of the folding function."
1283 )]
1284 #[doc_params(
1288 "The function to apply to each element and the accumulator.",
1289 "The initial value of the accumulator.",
1290 "The `TryThunk` to fold."
1291 )]
1292 fn fold_right<'a, FnBrand, E: 'a, B: 'a, Func>(
1307 func: Func,
1308 initial: B,
1309 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1310 ) -> B
1311 where
1312 Func: Fn(E, B) -> B + 'a,
1313 FnBrand: CloneableFn + 'a,
1314 {
1315 match fa.evaluate() {
1316 Err(e) => func(e, initial),
1317 Ok(_) => initial,
1318 }
1319 }
1320
1321 #[hm_signature(Foldable)]
1326 #[doc_type_params(
1330 "The lifetime of the computation.",
1331 "The brand of the cloneable function to use.",
1332 "The type of the elements in the structure.",
1333 "The type of the accumulator.",
1334 "The type of the folding function."
1335 )]
1336 #[doc_params(
1340 "The function to apply to the accumulator and each element.",
1341 "The initial value of the accumulator.",
1342 "The `TryThunk` to fold."
1343 )]
1344 fn fold_left<'a, FnBrand, E: 'a, B: 'a, Func>(
1359 func: Func,
1360 initial: B,
1361 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1362 ) -> B
1363 where
1364 Func: Fn(B, E) -> B + 'a,
1365 FnBrand: CloneableFn + 'a,
1366 {
1367 match fa.evaluate() {
1368 Err(e) => func(initial, e),
1369 Ok(_) => initial,
1370 }
1371 }
1372
1373 #[hm_signature(Foldable)]
1378 #[doc_type_params(
1382 "The lifetime of the computation.",
1383 "The brand of the cloneable function to use.",
1384 "The type of the elements in the structure.",
1385 "The type of the monoid.",
1386 "The type of the mapping function."
1387 )]
1388 #[doc_params("The mapping function.", "The Thunk to fold.")]
1392 fn fold_map<'a, FnBrand, E: 'a, M, Func>(
1407 func: Func,
1408 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1409 ) -> M
1410 where
1411 M: Monoid + 'a,
1412 Func: Fn(E) -> M + 'a,
1413 FnBrand: CloneableFn + 'a,
1414 {
1415 match fa.evaluate() {
1416 Err(e) => func(e),
1417 Ok(_) => M::empty(),
1418 }
1419 }
1420}
1421
1422#[cfg(test)]
1423mod tests {
1424 use super::*;
1425
1426 #[test]
1430 fn test_success() {
1431 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
1432 assert_eq!(try_thunk.evaluate(), Ok(42));
1433 }
1434
1435 #[test]
1439 fn test_failure() {
1440 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error");
1441 assert_eq!(try_thunk.evaluate(), Err("error"));
1442 }
1443
1444 #[test]
1448 fn test_map() {
1449 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).map(|x| x * 2);
1450 assert_eq!(try_thunk.evaluate(), Ok(42));
1451 }
1452
1453 #[test]
1457 fn test_map_err() {
1458 let try_thunk: TryThunk<i32, i32> = TryThunk::err(21).map_err(|x| x * 2);
1459 assert_eq!(try_thunk.evaluate(), Err(42));
1460 }
1461
1462 #[test]
1466 fn test_bind() {
1467 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).bind(|x| TryThunk::pure(x * 2));
1468 assert_eq!(try_thunk.evaluate(), Ok(42));
1469 }
1470
1471 #[test]
1475 fn test_borrowing() {
1476 let x = 42;
1477 let try_thunk: TryThunk<&i32, ()> = TryThunk::new(|| Ok(&x));
1478 assert_eq!(try_thunk.evaluate(), Ok(&42));
1479 }
1480
1481 #[test]
1485 fn test_bind_failure() {
1486 let try_thunk = TryThunk::<i32, &str>::err("error").bind(|x| TryThunk::pure(x * 2));
1487 assert_eq!(try_thunk.evaluate(), Err("error"));
1488 }
1489
1490 #[test]
1494 fn test_map_failure() {
1495 let try_thunk = TryThunk::<i32, &str>::err("error").map(|x| x * 2);
1496 assert_eq!(try_thunk.evaluate(), Err("error"));
1497 }
1498
1499 #[test]
1503 fn test_map_err_success() {
1504 let try_thunk = TryThunk::<i32, &str>::pure(42).map_err(|_| "new error");
1505 assert_eq!(try_thunk.evaluate(), Ok(42));
1506 }
1507
1508 #[test]
1510 fn test_try_thunk_from_memo() {
1511 use crate::types::RcLazy;
1512 let memo = RcLazy::new(|| 42);
1513 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1514 assert_eq!(try_thunk.evaluate(), Ok(42));
1515 }
1516
1517 #[test]
1519 fn test_try_thunk_from_try_memo() {
1520 use crate::types::RcTryLazy;
1521 let memo = RcTryLazy::new(|| Ok(42));
1522 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1523 assert_eq!(try_thunk.evaluate(), Ok(42));
1524 }
1525
1526 #[test]
1530 fn test_try_thunk_from_eval() {
1531 let eval = Thunk::pure(42);
1532 let try_thunk: TryThunk<i32, ()> = TryThunk::from(eval);
1533 assert_eq!(try_thunk.evaluate(), Ok(42));
1534 }
1535
1536 #[test]
1538 fn test_defer() {
1539 let try_thunk: TryThunk<i32, ()> = TryThunk::defer(|| TryThunk::pure(42));
1540 assert_eq!(try_thunk.evaluate(), Ok(42));
1541 }
1542
1543 #[test]
1547 fn test_catch() {
1548 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error").catch(|_| TryThunk::pure(42));
1549 assert_eq!(try_thunk.evaluate(), Ok(42));
1550 }
1551
1552 #[test]
1554 fn test_try_thunk_with_err_brand() {
1555 use crate::{brands::*, functions::*};
1556
1557 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1559 let mapped = map::<TryThunkWithErrBrand<()>, _, _, _>(|x| x * 2, try_thunk);
1560 assert_eq!(mapped.evaluate(), Ok(20));
1561
1562 let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(42);
1564 assert_eq!(try_thunk.evaluate(), Ok(42));
1565
1566 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1568 let bound = bind::<TryThunkWithErrBrand<()>, _, _, _>(try_thunk, |x| {
1569 pure::<TryThunkWithErrBrand<()>, _>(x * 2)
1570 });
1571 assert_eq!(bound.evaluate(), Ok(20));
1572
1573 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1575 let folded = fold_right::<RcFnBrand, TryThunkWithErrBrand<()>, _, _, _>(
1576 |x, acc| x + acc,
1577 5,
1578 try_thunk,
1579 );
1580 assert_eq!(folded, 15);
1581 }
1582
1583 #[test]
1585 fn test_bifunctor() {
1586 use crate::{brands::*, classes::bifunctor::*};
1587
1588 let x: TryThunk<i32, i32> = TryThunk::pure(5);
1589 assert_eq!(
1590 bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, x).evaluate(),
1591 Ok(10)
1592 );
1593
1594 let y: TryThunk<i32, i32> = TryThunk::err(5);
1595 assert_eq!(
1596 bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, y).evaluate(),
1597 Err(6)
1598 );
1599 }
1600
1601 #[test]
1603 fn test_try_thunk_with_ok_brand() {
1604 use crate::{brands::*, functions::*};
1605
1606 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1608 let mapped = map::<TryThunkWithOkBrand<i32>, _, _, _>(|x| x * 2, try_thunk);
1609 assert_eq!(mapped.evaluate(), Err(20));
1610
1611 let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(42);
1613 assert_eq!(try_thunk.evaluate(), Err(42));
1614
1615 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1617 let bound = bind::<TryThunkWithOkBrand<i32>, _, _, _>(try_thunk, |x| {
1618 pure::<TryThunkWithOkBrand<i32>, _>(x * 2)
1619 });
1620 assert_eq!(bound.evaluate(), Err(20));
1621
1622 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1624 let folded = fold_right::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _, _>(
1625 |x, acc| x + acc,
1626 5,
1627 try_thunk,
1628 );
1629 assert_eq!(folded, 15);
1630 }
1631}