1#[fp_macros::document_module]
6mod inner {
7 use crate::{
8 Apply,
9 brands::{TryThunkBrand, TryThunkWithErrBrand, TryThunkWithOkBrand},
10 classes::{
11 ApplyFirst, ApplySecond, Bifunctor, CloneableFn, Deferrable, Foldable, Functor, Lift,
12 MonadRec, Monoid, Pointed, Semiapplicative, Semigroup, Semimonad,
13 },
14 impl_kind,
15 kinds::*,
16 types::{Lazy, LazyConfig, Step, Thunk, TryLazy},
17 };
18 use fp_macros::{document_fields, document_parameters, document_type_parameters};
19
20 #[document_type_parameters(
26 "The lifetime of the computation.",
27 "The type of the value produced by the computation on success.",
28 "The type of the error produced by the computation on failure."
29 )]
30 #[document_fields("The closure that performs the computation.")]
41 pub struct TryThunk<'a, A, E>(Box<dyn FnOnce() -> Result<A, E> + 'a>);
57
58 #[document_type_parameters(
61 "The lifetime of the computation.",
62 "The type of the success value.",
63 "The type of the error value."
64 )]
65 #[document_parameters("The `TryThunk` instance.")]
66 impl<'a, A: 'a, E: 'a> TryThunk<'a, A, E> {
67 #[document_signature]
72 #[document_type_parameters("The type of the thunk.")]
76 #[document_parameters("The thunk to wrap.")]
80 pub fn new<F>(f: F) -> Self
94 where
95 F: FnOnce() -> Result<A, E> + 'a,
96 {
97 TryThunk(Box::new(f))
98 }
99
100 #[document_signature]
105 #[document_parameters("The value to wrap.")]
109 pub fn pure(a: A) -> Self
123 where
124 A: 'a,
125 {
126 TryThunk::new(move || Ok(a))
127 }
128
129 #[document_signature]
134 #[document_type_parameters("The type of the thunk.")]
138 #[document_parameters("The thunk that returns a `TryThunk`.")]
142 pub fn defer<F>(f: F) -> Self
156 where
157 F: FnOnce() -> TryThunk<'a, A, E> + 'a,
158 {
159 TryThunk::new(move || f().evaluate())
160 }
161
162 #[document_signature]
169 #[document_parameters("The value to wrap.")]
173 pub fn ok(a: A) -> Self
187 where
188 A: 'a,
189 {
190 Self::pure(a)
191 }
192
193 #[document_signature]
198 #[document_parameters("The error to wrap.")]
202 pub fn err(e: E) -> Self
216 where
217 E: 'a,
218 {
219 TryThunk::new(move || Err(e))
220 }
221
222 #[document_signature]
227 #[document_type_parameters(
231 "The type of the result of the new computation.",
232 "The type of the function to apply."
233 )]
234 #[document_parameters("The function to apply to the result of the computation.")]
238 pub fn bind<B: 'a, F>(
252 self,
253 f: F,
254 ) -> TryThunk<'a, B, E>
255 where
256 F: FnOnce(A) -> TryThunk<'a, B, E> + 'a,
257 {
258 TryThunk::new(move || match (self.0)() {
259 Ok(a) => (f(a).0)(),
260 Err(e) => Err(e),
261 })
262 }
263
264 #[document_signature]
269 #[document_type_parameters(
273 "The type of the result of the transformation.",
274 "The type of the transformation function."
275 )]
276 #[document_parameters("The function to apply to the result of the computation.")]
280 pub fn map<B: 'a, Func>(
294 self,
295 func: Func,
296 ) -> TryThunk<'a, B, E>
297 where
298 Func: FnOnce(A) -> B + 'a,
299 {
300 TryThunk::new(move || (self.0)().map(func))
301 }
302
303 #[document_signature]
308 #[document_type_parameters(
312 "The type of the new error.",
313 "The type of the transformation function."
314 )]
315 #[document_parameters("The function to apply to the error.")]
319 pub fn map_err<E2: 'a, F>(
333 self,
334 f: F,
335 ) -> TryThunk<'a, A, E2>
336 where
337 F: FnOnce(E) -> E2 + 'a,
338 {
339 TryThunk::new(move || (self.0)().map_err(f))
340 }
341
342 #[document_signature]
347 #[document_type_parameters("The type of the recovery function.")]
351 #[document_parameters("The function to apply to the error value.")]
355 pub fn catch<F>(
370 self,
371 f: F,
372 ) -> Self
373 where
374 F: FnOnce(E) -> TryThunk<'a, A, E> + 'a,
375 {
376 TryThunk::new(move || match (self.0)() {
377 Ok(a) => Ok(a),
378 Err(e) => (f(e).0)(),
379 })
380 }
381
382 #[document_signature]
387 pub fn evaluate(self) -> Result<A, E> {
401 (self.0)()
402 }
403 }
404
405 #[document_type_parameters(
408 "The lifetime of the computation.",
409 "The type of the success value.",
410 "The type of the error value.",
411 "The memoization configuration."
412 )]
413 impl<'a, A, E, Config> From<Lazy<'a, A, Config>> for TryThunk<'a, A, E>
414 where
415 A: Clone + 'a,
416 E: 'a,
417 Config: LazyConfig,
418 {
419 #[document_signature]
422 #[document_parameters("The lazy value to convert.")]
426 fn from(memo: Lazy<'a, A, Config>) -> Self {
427 TryThunk::new(move || Ok(memo.evaluate().clone()))
428 }
429 }
430
431 #[document_type_parameters(
434 "The lifetime of the computation.",
435 "The type of the success value.",
436 "The type of the error value.",
437 "The memoization configuration."
438 )]
439 impl<'a, A, E, Config> From<TryLazy<'a, A, E, Config>> for TryThunk<'a, A, E>
440 where
441 A: Clone + 'a,
442 E: Clone + 'a,
443 Config: LazyConfig,
444 {
445 #[document_signature]
448 #[document_parameters("The fallible lazy value to convert.")]
452 fn from(memo: TryLazy<'a, A, E, Config>) -> Self {
453 TryThunk::new(move || memo.evaluate().cloned().map_err(Clone::clone))
454 }
455 }
456
457 #[document_type_parameters(
460 "The lifetime of the computation.",
461 "The type of the success value.",
462 "The type of the error value."
463 )]
464 impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E> {
465 #[document_signature]
468 #[document_parameters("The thunk to convert.")]
472 fn from(eval: Thunk<'a, A>) -> Self {
473 TryThunk::new(move || Ok(eval.evaluate()))
474 }
475 }
476
477 #[document_type_parameters(
480 "The lifetime of the computation.",
481 "The type of the success value.",
482 "The type of the error value."
483 )]
484 impl<'a, A, E> Deferrable<'a> for TryThunk<'a, A, E>
485 where
486 A: 'a,
487 E: 'a,
488 {
489 #[document_signature]
494 #[document_type_parameters("The type of the thunk.")]
498 #[document_parameters("A thunk that produces the try thunk.")]
502 fn defer<F>(f: F) -> Self
516 where
517 F: FnOnce() -> Self + 'a,
518 Self: Sized,
519 {
520 TryThunk::defer(f)
521 }
522 }
523
524 impl_kind! {
525 impl<E: 'static> for TryThunkWithErrBrand<E> {
526 #[document_default]
527 type Of<'a, A: 'a>: 'a = TryThunk<'a, A, E>;
528 }
529 }
530
531 #[document_type_parameters("The error type.")]
534 impl<E: 'static> Functor for TryThunkWithErrBrand<E> {
535 #[document_signature]
540 #[document_type_parameters(
544 "The lifetime of the computation.",
545 "The type of the value inside the `TryThunk`.",
546 "The type of the result of the transformation.",
547 "The type of the transformation function."
548 )]
549 #[document_parameters(
553 "The function to apply to the result of the computation.",
554 "The `TryThunk` instance."
555 )]
556 fn map<'a, A: 'a, B: 'a, Func>(
571 func: Func,
572 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
573 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
574 where
575 Func: Fn(A) -> B + 'a,
576 {
577 fa.map(func)
578 }
579 }
580
581 #[document_type_parameters("The error type.")]
584 impl<E: 'static> Pointed for TryThunkWithErrBrand<E> {
585 #[document_signature]
590 #[document_type_parameters(
594 "The lifetime of the computation.",
595 "The type of the value to wrap."
596 )]
597 #[document_parameters("The value to wrap.")]
601 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
615 TryThunk::pure(a)
616 }
617 }
618
619 #[document_type_parameters("The error type.")]
622 impl<E: 'static> Lift for TryThunkWithErrBrand<E> {
623 #[document_signature]
628 #[document_type_parameters(
632 "The lifetime of the computation.",
633 "The type of the first value.",
634 "The type of the second value.",
635 "The type of the result.",
636 "The type of the binary function."
637 )]
638 #[document_parameters(
642 "The binary function to apply.",
643 "The first `TryThunk`.",
644 "The second `TryThunk`."
645 )]
646 fn lift2<'a, A, B, C, Func>(
662 func: Func,
663 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
664 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
665 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
666 where
667 Func: Fn(A, B) -> C + 'a,
668 A: Clone + 'a,
669 B: Clone + 'a,
670 C: 'a,
671 {
672 fa.bind(move |a| fb.map(move |b| func(a, b)))
673 }
674 }
675
676 #[document_type_parameters("The error type.")]
679 impl<E: 'static> ApplyFirst for TryThunkWithErrBrand<E> {}
680
681 #[document_type_parameters("The error type.")]
684 impl<E: 'static> ApplySecond for TryThunkWithErrBrand<E> {}
685
686 #[document_type_parameters("The error type.")]
689 impl<E: 'static> Semiapplicative for TryThunkWithErrBrand<E> {
690 #[document_signature]
695 #[document_type_parameters(
699 "The lifetime of the computation.",
700 "The brand of the cloneable function wrapper.",
701 "The type of the input.",
702 "The type of the result."
703 )]
704 #[document_parameters(
708 "The `TryThunk` containing the function.",
709 "The `TryThunk` containing the value."
710 )]
711 fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
727 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
728 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
729 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
730 ff.bind(move |f| {
731 fa.map(
732 #[allow(clippy::redundant_closure)] move |a| f(a),
734 )
735 })
736 }
737 }
738
739 #[document_type_parameters("The error type.")]
742 impl<E: 'static> Semimonad for TryThunkWithErrBrand<E> {
743 #[document_signature]
748 #[document_type_parameters(
752 "The lifetime of the computation.",
753 "The type of the result of the first computation.",
754 "The type of the result of the new computation.",
755 "The type of the function to apply."
756 )]
757 #[document_parameters(
761 "The first `TryThunk`.",
762 "The function to apply to the result of the computation."
763 )]
764 fn bind<'a, A: 'a, B: 'a, Func>(
779 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
780 func: Func,
781 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
782 where
783 Func: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
784 {
785 ma.bind(func)
786 }
787 }
788
789 #[document_type_parameters("The error type.")]
792 impl<E: 'static> MonadRec for TryThunkWithErrBrand<E> {
793 #[document_signature]
798 #[document_type_parameters(
802 "The lifetime of the computation.",
803 "The type of the initial value and loop state.",
804 "The type of the result.",
805 "The type of the step function."
806 )]
807 #[document_parameters("The step function.", "The initial value.")]
811 fn tail_rec_m<'a, A: 'a, B: 'a, F>(
828 f: F,
829 a: A,
830 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
831 where
832 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Step<A, B>>)
833 + Clone
834 + 'a,
835 {
836 TryThunk::new(move || {
837 let mut current = a;
838 loop {
839 match f(current).evaluate() {
840 Ok(Step::Loop(next)) => current = next,
841 Ok(Step::Done(res)) => break Ok(res),
842 Err(e) => break Err(e),
843 }
844 }
845 })
846 }
847 }
848
849 #[document_type_parameters("The error type.")]
852 impl<E: 'static> Foldable for TryThunkWithErrBrand<E> {
853 #[document_signature]
858 #[document_type_parameters(
862 "The lifetime of the computation.",
863 "The brand of the cloneable function to use.",
864 "The type of the elements in the structure.",
865 "The type of the accumulator.",
866 "The type of the folding function."
867 )]
868 #[document_parameters(
872 "The function to apply to each element and the accumulator.",
873 "The initial value of the accumulator.",
874 "The `TryThunk` to fold."
875 )]
876 fn fold_right<'a, FnBrand, A: 'a, B: 'a, Func>(
891 func: Func,
892 initial: B,
893 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
894 ) -> B
895 where
896 Func: Fn(A, B) -> B + 'a,
897 FnBrand: CloneableFn + 'a,
898 {
899 match fa.evaluate() {
900 Ok(a) => func(a, initial),
901 Err(_) => initial,
902 }
903 }
904
905 #[document_signature]
910 #[document_type_parameters(
914 "The lifetime of the computation.",
915 "The brand of the cloneable function to use.",
916 "The type of the elements in the structure.",
917 "The type of the accumulator.",
918 "The type of the folding function."
919 )]
920 #[document_parameters(
924 "The function to apply to the accumulator and each element.",
925 "The initial value of the accumulator.",
926 "The `TryThunk` to fold."
927 )]
928 fn fold_left<'a, FnBrand, A: 'a, B: 'a, Func>(
943 func: Func,
944 initial: B,
945 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
946 ) -> B
947 where
948 Func: Fn(B, A) -> B + 'a,
949 FnBrand: CloneableFn + 'a,
950 {
951 match fa.evaluate() {
952 Ok(a) => func(initial, a),
953 Err(_) => initial,
954 }
955 }
956
957 #[document_signature]
962 #[document_type_parameters(
966 "The lifetime of the computation.",
967 "The brand of the cloneable function to use.",
968 "The type of the elements in the structure.",
969 "The type of the monoid.",
970 "The type of the mapping function."
971 )]
972 #[document_parameters("The mapping function.", "The Thunk to fold.")]
976 fn fold_map<'a, FnBrand, A: 'a, M, Func>(
991 func: Func,
992 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
993 ) -> M
994 where
995 M: Monoid + 'a,
996 Func: Fn(A) -> M + 'a,
997 FnBrand: CloneableFn + 'a,
998 {
999 match fa.evaluate() {
1000 Ok(a) => func(a),
1001 Err(_) => M::empty(),
1002 }
1003 }
1004 }
1005
1006 #[document_type_parameters(
1009 "The lifetime of the computation.",
1010 "The success value type.",
1011 "The error value type."
1012 )]
1013 impl<'a, A: Semigroup + 'a, E: 'a> Semigroup for TryThunk<'a, A, E> {
1014 #[document_signature]
1019 #[document_parameters("The first `TryThunk`.", "The second `TryThunk`.")]
1023 fn append(
1039 a: Self,
1040 b: Self,
1041 ) -> Self {
1042 TryThunk::new(move || match (a.evaluate(), b.evaluate()) {
1043 (Ok(a_val), Ok(b_val)) => Ok(Semigroup::append(a_val, b_val)),
1044 (Err(e), _) => Err(e),
1045 (_, Err(e)) => Err(e),
1046 })
1047 }
1048 }
1049
1050 #[document_type_parameters(
1053 "The lifetime of the computation.",
1054 "The success value type.",
1055 "The error value type."
1056 )]
1057 impl<'a, A: Monoid + 'a, E: 'a> Monoid for TryThunk<'a, A, E> {
1058 #[document_signature]
1063 fn empty() -> Self {
1077 TryThunk::new(|| Ok(Monoid::empty()))
1078 }
1079 }
1080
1081 impl_kind! {
1082 for TryThunkBrand {
1089 type Of<'a, E: 'a, A: 'a>: 'a = TryThunk<'a, A, E>;
1090 }
1091 }
1092
1093 impl Bifunctor for TryThunkBrand {
1094 #[document_signature]
1101 #[document_type_parameters(
1105 "The lifetime of the values.",
1106 "The type of the error value.",
1107 "The type of the mapped error value.",
1108 "The type of the success value.",
1109 "The type of the mapped success value.",
1110 "The type of the function to apply to the error.",
1111 "The type of the function to apply to the success."
1112 )]
1113 #[document_parameters(
1117 "The function to apply to the error.",
1118 "The function to apply to the success.",
1119 "The `TryThunk` to map over."
1120 )]
1121 fn bimap<'a, A: 'a, B: 'a, C: 'a, D: 'a, F, G>(
1138 f: F,
1139 g: G,
1140 p: Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
1141 ) -> Apply!(<Self as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, D>)
1142 where
1143 F: Fn(A) -> B + 'a,
1144 G: Fn(C) -> D + 'a,
1145 {
1146 TryThunk::new(move || match p.evaluate() {
1147 Ok(c) => Ok(g(c)),
1148 Err(a) => Err(f(a)),
1149 })
1150 }
1151 }
1152
1153 impl_kind! {
1154 impl<A: 'static> for TryThunkWithOkBrand<A> {
1155 #[document_default]
1156 type Of<'a, E: 'a>: 'a = TryThunk<'a, A, E>;
1157 }
1158 }
1159
1160 #[document_type_parameters("The success type.")]
1163 impl<A: 'static> Functor for TryThunkWithOkBrand<A> {
1164 #[document_signature]
1169 #[document_type_parameters(
1173 "The lifetime of the computation.",
1174 "The type of the error value inside the `TryThunk`.",
1175 "The type of the result of the transformation.",
1176 "The type of the transformation function."
1177 )]
1178 #[document_parameters("The function to apply to the error.", "The `TryThunk` instance.")]
1182 fn map<'a, E: 'a, E2: 'a, Func>(
1197 func: Func,
1198 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1199 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>)
1200 where
1201 Func: Fn(E) -> E2 + 'a,
1202 {
1203 fa.map_err(func)
1204 }
1205 }
1206
1207 #[document_type_parameters("The success type.")]
1210 impl<A: 'static> Pointed for TryThunkWithOkBrand<A> {
1211 #[document_signature]
1216 #[document_type_parameters(
1220 "The lifetime of the computation.",
1221 "The type of the value to wrap."
1222 )]
1223 #[document_parameters("The value to wrap.")]
1227 fn pure<'a, E: 'a>(e: E) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>) {
1241 TryThunk::err(e)
1242 }
1243 }
1244
1245 #[document_type_parameters("The success type.")]
1248 impl<A: 'static> Lift for TryThunkWithOkBrand<A> {
1249 #[document_signature]
1254 #[document_type_parameters(
1258 "The lifetime of the computation.",
1259 "The type of the first error value.",
1260 "The type of the second error value.",
1261 "The type of the result error value.",
1262 "The type of the binary function."
1263 )]
1264 #[document_parameters(
1268 "The binary function to apply to the errors.",
1269 "The first `TryThunk`.",
1270 "The second `TryThunk`."
1271 )]
1272 fn lift2<'a, E1, E2, E3, Func>(
1288 func: Func,
1289 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1290 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>),
1291 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E3>)
1292 where
1293 Func: Fn(E1, E2) -> E3 + 'a,
1294 E1: Clone + 'a,
1295 E2: Clone + 'a,
1296 E3: 'a,
1297 {
1298 TryThunk::new(move || match (fa.evaluate(), fb.evaluate()) {
1299 (Err(e1), Err(e2)) => Err(func(e1, e2)),
1300 (Ok(a), _) => Ok(a),
1301 (_, Ok(a)) => Ok(a),
1302 })
1303 }
1304 }
1305
1306 #[document_type_parameters("The success type.")]
1309 impl<A: 'static> ApplyFirst for TryThunkWithOkBrand<A> {}
1310
1311 #[document_type_parameters("The success type.")]
1314 impl<A: 'static> ApplySecond for TryThunkWithOkBrand<A> {}
1315
1316 #[document_type_parameters("The success type.")]
1319 impl<A: 'static> Semiapplicative for TryThunkWithOkBrand<A> {
1320 #[document_signature]
1325 #[document_type_parameters(
1329 "The lifetime of the computation.",
1330 "The brand of the cloneable function wrapper.",
1331 "The type of the input error.",
1332 "The type of the result error."
1333 )]
1334 #[document_parameters(
1338 "The `TryThunk` containing the function (in Err).",
1339 "The `TryThunk` containing the value (in Err)."
1340 )]
1341 fn apply<'a, FnBrand: 'a + CloneableFn, E1: 'a + Clone, E2: 'a>(
1357 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, E1, E2>>),
1358 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1359 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) {
1360 TryThunk::new(move || match (ff.evaluate(), fa.evaluate()) {
1361 (Err(f), Err(e)) => Err(f(e)),
1362 (Ok(a), _) => Ok(a),
1363 (_, Ok(a)) => Ok(a),
1364 })
1365 }
1366 }
1367
1368 #[document_type_parameters("The success type.")]
1371 impl<A: 'static> Semimonad for TryThunkWithOkBrand<A> {
1372 #[document_signature]
1377 #[document_type_parameters(
1381 "The lifetime of the computation.",
1382 "The type of the result of the first computation (error).",
1383 "The type of the result of the new computation (error).",
1384 "The type of the function to apply."
1385 )]
1386 #[document_parameters(
1390 "The first `TryThunk`.",
1391 "The function to apply to the error result of the computation."
1392 )]
1393 fn bind<'a, E1: 'a, E2: 'a, Func>(
1408 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E1>),
1409 func: Func,
1410 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>)
1411 where
1412 Func: Fn(E1) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E2>) + 'a,
1413 {
1414 TryThunk::new(move || match ma.evaluate() {
1415 Ok(a) => Ok(a),
1416 Err(e) => func(e).evaluate(),
1417 })
1418 }
1419 }
1420
1421 #[document_type_parameters("The success type.")]
1424 impl<A: 'static> Foldable for TryThunkWithOkBrand<A> {
1425 #[document_signature]
1430 #[document_type_parameters(
1434 "The lifetime of the computation.",
1435 "The brand of the cloneable function to use.",
1436 "The type of the elements in the structure.",
1437 "The type of the accumulator.",
1438 "The type of the folding function."
1439 )]
1440 #[document_parameters(
1444 "The function to apply to each element and the accumulator.",
1445 "The initial value of the accumulator.",
1446 "The `TryThunk` to fold."
1447 )]
1448 fn fold_right<'a, FnBrand, E: 'a, B: 'a, Func>(
1463 func: Func,
1464 initial: B,
1465 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1466 ) -> B
1467 where
1468 Func: Fn(E, B) -> B + 'a,
1469 FnBrand: CloneableFn + 'a,
1470 {
1471 match fa.evaluate() {
1472 Err(e) => func(e, initial),
1473 Ok(_) => initial,
1474 }
1475 }
1476
1477 #[document_signature]
1482 #[document_type_parameters(
1486 "The lifetime of the computation.",
1487 "The brand of the cloneable function to use.",
1488 "The type of the elements in the structure.",
1489 "The type of the accumulator.",
1490 "The type of the folding function."
1491 )]
1492 #[document_parameters(
1496 "The function to apply to the accumulator and each element.",
1497 "The initial value of the accumulator.",
1498 "The `TryThunk` to fold."
1499 )]
1500 fn fold_left<'a, FnBrand, E: 'a, B: 'a, Func>(
1515 func: Func,
1516 initial: B,
1517 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1518 ) -> B
1519 where
1520 Func: Fn(B, E) -> B + 'a,
1521 FnBrand: CloneableFn + 'a,
1522 {
1523 match fa.evaluate() {
1524 Err(e) => func(initial, e),
1525 Ok(_) => initial,
1526 }
1527 }
1528
1529 #[document_signature]
1534 #[document_type_parameters(
1538 "The lifetime of the computation.",
1539 "The brand of the cloneable function to use.",
1540 "The type of the elements in the structure.",
1541 "The type of the monoid.",
1542 "The type of the mapping function."
1543 )]
1544 #[document_parameters("The mapping function.", "The Thunk to fold.")]
1548 fn fold_map<'a, FnBrand, E: 'a, M, Func>(
1563 func: Func,
1564 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
1565 ) -> M
1566 where
1567 M: Monoid + 'a,
1568 Func: Fn(E) -> M + 'a,
1569 FnBrand: CloneableFn + 'a,
1570 {
1571 match fa.evaluate() {
1572 Err(e) => func(e),
1573 Ok(_) => M::empty(),
1574 }
1575 }
1576 }
1577}
1578pub use inner::*;
1579
1580#[cfg(test)]
1581mod tests {
1582 use crate::types::Thunk;
1583
1584 use super::*;
1585
1586 #[test]
1590 fn test_success() {
1591 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
1592 assert_eq!(try_thunk.evaluate(), Ok(42));
1593 }
1594
1595 #[test]
1599 fn test_failure() {
1600 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error");
1601 assert_eq!(try_thunk.evaluate(), Err("error"));
1602 }
1603
1604 #[test]
1608 fn test_map() {
1609 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).map(|x| x * 2);
1610 assert_eq!(try_thunk.evaluate(), Ok(42));
1611 }
1612
1613 #[test]
1617 fn test_map_err() {
1618 let try_thunk: TryThunk<i32, i32> = TryThunk::err(21).map_err(|x| x * 2);
1619 assert_eq!(try_thunk.evaluate(), Err(42));
1620 }
1621
1622 #[test]
1626 fn test_bind() {
1627 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).bind(|x| TryThunk::pure(x * 2));
1628 assert_eq!(try_thunk.evaluate(), Ok(42));
1629 }
1630
1631 #[test]
1635 fn test_borrowing() {
1636 let x = 42;
1637 let try_thunk: TryThunk<&i32, ()> = TryThunk::new(|| Ok(&x));
1638 assert_eq!(try_thunk.evaluate(), Ok(&42));
1639 }
1640
1641 #[test]
1645 fn test_bind_failure() {
1646 let try_thunk = TryThunk::<i32, &str>::err("error").bind(|x| TryThunk::pure(x * 2));
1647 assert_eq!(try_thunk.evaluate(), Err("error"));
1648 }
1649
1650 #[test]
1654 fn test_map_failure() {
1655 let try_thunk = TryThunk::<i32, &str>::err("error").map(|x| x * 2);
1656 assert_eq!(try_thunk.evaluate(), Err("error"));
1657 }
1658
1659 #[test]
1663 fn test_map_err_success() {
1664 let try_thunk = TryThunk::<i32, &str>::pure(42).map_err(|_| "new error");
1665 assert_eq!(try_thunk.evaluate(), Ok(42));
1666 }
1667
1668 #[test]
1670 fn test_try_thunk_from_memo() {
1671 use crate::types::RcLazy;
1672 let memo = RcLazy::new(|| 42);
1673 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1674 assert_eq!(try_thunk.evaluate(), Ok(42));
1675 }
1676
1677 #[test]
1679 fn test_try_thunk_from_try_memo() {
1680 use crate::types::RcTryLazy;
1681 let memo = RcTryLazy::new(|| Ok(42));
1682 let try_thunk: TryThunk<i32, ()> = TryThunk::from(memo);
1683 assert_eq!(try_thunk.evaluate(), Ok(42));
1684 }
1685
1686 #[test]
1690 fn test_try_thunk_from_eval() {
1691 let eval = Thunk::pure(42);
1692 let try_thunk: TryThunk<i32, ()> = TryThunk::from(eval);
1693 assert_eq!(try_thunk.evaluate(), Ok(42));
1694 }
1695
1696 #[test]
1698 fn test_defer() {
1699 let try_thunk: TryThunk<i32, ()> = TryThunk::defer(|| TryThunk::pure(42));
1700 assert_eq!(try_thunk.evaluate(), Ok(42));
1701 }
1702
1703 #[test]
1707 fn test_catch() {
1708 let try_thunk: TryThunk<i32, &str> = TryThunk::err("error").catch(|_| TryThunk::pure(42));
1709 assert_eq!(try_thunk.evaluate(), Ok(42));
1710 }
1711
1712 #[test]
1714 fn test_try_thunk_with_err_brand() {
1715 use crate::{brands::*, functions::*};
1716
1717 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1719 let mapped = map::<TryThunkWithErrBrand<()>, _, _, _>(|x| x * 2, try_thunk);
1720 assert_eq!(mapped.evaluate(), Ok(20));
1721
1722 let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(42);
1724 assert_eq!(try_thunk.evaluate(), Ok(42));
1725
1726 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1728 let bound = bind::<TryThunkWithErrBrand<()>, _, _, _>(try_thunk, |x| {
1729 pure::<TryThunkWithErrBrand<()>, _>(x * 2)
1730 });
1731 assert_eq!(bound.evaluate(), Ok(20));
1732
1733 let try_thunk: TryThunk<i32, ()> = TryThunk::pure(10);
1735 let folded = fold_right::<RcFnBrand, TryThunkWithErrBrand<()>, _, _, _>(
1736 |x, acc| x + acc,
1737 5,
1738 try_thunk,
1739 );
1740 assert_eq!(folded, 15);
1741 }
1742
1743 #[test]
1745 fn test_bifunctor() {
1746 use crate::{brands::*, classes::bifunctor::*};
1747
1748 let x: TryThunk<i32, i32> = TryThunk::pure(5);
1749 assert_eq!(
1750 bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, x).evaluate(),
1751 Ok(10)
1752 );
1753
1754 let y: TryThunk<i32, i32> = TryThunk::err(5);
1755 assert_eq!(
1756 bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, y).evaluate(),
1757 Err(6)
1758 );
1759 }
1760
1761 #[test]
1763 fn test_try_thunk_with_ok_brand() {
1764 use crate::{brands::*, functions::*};
1765
1766 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1768 let mapped = map::<TryThunkWithOkBrand<i32>, _, _, _>(|x| x * 2, try_thunk);
1769 assert_eq!(mapped.evaluate(), Err(20));
1770
1771 let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(42);
1773 assert_eq!(try_thunk.evaluate(), Err(42));
1774
1775 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1777 let bound = bind::<TryThunkWithOkBrand<i32>, _, _, _>(try_thunk, |x| {
1778 pure::<TryThunkWithOkBrand<i32>, _>(x * 2)
1779 });
1780 assert_eq!(bound.evaluate(), Err(20));
1781
1782 let try_thunk: TryThunk<i32, i32> = TryThunk::err(10);
1784 let folded = fold_right::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _, _>(
1785 |x, acc| x + acc,
1786 5,
1787 try_thunk,
1788 );
1789 assert_eq!(folded, 15);
1790 }
1791}