Skip to main content

fp_library/types/
try_thunk.rs

1//! Deferred, non-memoized fallible computation with higher-kinded type support.
2//!
3//! The fallible counterpart to [`Thunk`](crate::types::Thunk). Each call to [`TryThunk::evaluate`] re-executes the computation and returns a [`Result`]. Supports borrowing and lifetime polymorphism.
4
5#[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	/// A deferred computation that may fail with error type `E`.
21	///
22	/// Like [`Thunk`], this is NOT memoized. Each [`TryThunk::evaluate`] re-executes.
23	/// Unlike [`Thunk`], the result is [`Result<A, E>`].
24	///
25	#[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	///
31	/// ### Higher-Kinded Type Representation
32	///
33	/// This type has multiple higher-kinded representations:
34	/// - [`TryThunkBrand`](crate::brands::TryThunkBrand): fully polymorphic over both error and success types (bifunctor).
35	/// - [`TryThunkWithErrBrand<E>`](crate::brands::TryThunkWithErrBrand): the error type is fixed, polymorphic over the success type (functor over `Ok`).
36	/// - [`TryThunkWithOkBrand<A>`](crate::brands::TryThunkWithOkBrand): the success type is fixed, polymorphic over the error type (functor over `Err`).
37	///
38	/// ### Fields
39	///
40	#[document_fields("The closure that performs the computation.")]
41	///
42	/// ### Examples
43	///
44	/// ```
45	/// use fp_library::types::*;
46	///
47	/// let computation: TryThunk<i32, &str> = TryThunk::new(|| {
48	///     Ok(42)
49	/// });
50	///
51	/// match computation.evaluate() {
52	///     Ok(val) => assert_eq!(val, 42),
53	///     Err(_) => panic!("Should not fail"),
54	/// }
55	/// ```
56	pub struct TryThunk<'a, A, E>(Box<dyn FnOnce() -> Result<A, E> + 'a>);
57
58	/// ### Type Parameters
59	///
60	#[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		/// Creates a new `TryThunk` from a thunk.
68		///
69		/// ### Type Signature
70		///
71		#[document_signature]
72		///
73		/// ### Type Parameters
74		///
75		#[document_type_parameters("The type of the thunk.")]
76		///
77		/// ### Parameters
78		///
79		#[document_parameters("The thunk to wrap.")]
80		///
81		/// ### Returns
82		///
83		/// A new `TryThunk` instance.
84		///
85		/// ### Examples
86		///
87		/// ```
88		/// use fp_library::types::*;
89		///
90		/// let try_thunk: TryThunk<i32, ()> = TryThunk::new(|| Ok(42));
91		/// assert_eq!(try_thunk.evaluate(), Ok(42));
92		/// ```
93		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		/// Returns a pure value (already computed).
101		///
102		/// ### Type Signature
103		///
104		#[document_signature]
105		///
106		/// ### Parameters
107		///
108		#[document_parameters("The value to wrap.")]
109		///
110		/// ### Returns
111		///
112		/// A new `TryThunk` instance containing the value.
113		///
114		/// ### Examples
115		///
116		/// ```
117		/// use fp_library::types::*;
118		///
119		/// let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
120		/// assert_eq!(try_thunk.evaluate(), Ok(42));
121		/// ```
122		pub fn pure(a: A) -> Self
123		where
124			A: 'a,
125		{
126			TryThunk::new(move || Ok(a))
127		}
128
129		/// Defers a computation that returns a TryThunk.
130		///
131		/// ### Type Signature
132		///
133		#[document_signature]
134		///
135		/// ### Type Parameters
136		///
137		#[document_type_parameters("The type of the thunk.")]
138		///
139		/// ### Parameters
140		///
141		#[document_parameters("The thunk that returns a `TryThunk`.")]
142		///
143		/// ### Returns
144		///
145		/// A new `TryThunk` instance.
146		///
147		/// ### Examples
148		///
149		/// ```
150		/// use fp_library::types::*;
151		///
152		/// let try_thunk: TryThunk<i32, ()> = TryThunk::defer(|| TryThunk::pure(42));
153		/// assert_eq!(try_thunk.evaluate(), Ok(42));
154		/// ```
155		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		/// Alias for [`pure`](Self::pure).
163		///
164		/// Creates a successful computation.
165		///
166		/// ### Type Signature
167		///
168		#[document_signature]
169		///
170		/// ### Parameters
171		///
172		#[document_parameters("The value to wrap.")]
173		///
174		/// ### Returns
175		///
176		/// A new `TryThunk` instance containing the value.
177		///
178		/// ### Examples
179		///
180		/// ```
181		/// use fp_library::types::*;
182		///
183		/// let try_thunk: TryThunk<i32, ()> = TryThunk::ok(42);
184		/// assert_eq!(try_thunk.evaluate(), Ok(42));
185		/// ```
186		pub fn ok(a: A) -> Self
187		where
188			A: 'a,
189		{
190			Self::pure(a)
191		}
192
193		/// Returns a pure error.
194		///
195		/// ### Type Signature
196		///
197		#[document_signature]
198		///
199		/// ### Parameters
200		///
201		#[document_parameters("The error to wrap.")]
202		///
203		/// ### Returns
204		///
205		/// A new `TryThunk` instance containing the error.
206		///
207		/// ### Examples
208		///
209		/// ```
210		/// use fp_library::types::*;
211		///
212		/// let try_thunk: TryThunk<i32, &str> = TryThunk::err("error");
213		/// assert_eq!(try_thunk.evaluate(), Err("error"));
214		/// ```
215		pub fn err(e: E) -> Self
216		where
217			E: 'a,
218		{
219			TryThunk::new(move || Err(e))
220		}
221
222		/// Monadic bind: chains computations.
223		///
224		/// ### Type Signature
225		///
226		#[document_signature]
227		///
228		/// ### Type Parameters
229		///
230		#[document_type_parameters(
231			"The type of the result of the new computation.",
232			"The type of the function to apply."
233		)]
234		///
235		/// ### Parameters
236		///
237		#[document_parameters("The function to apply to the result of the computation.")]
238		///
239		/// ### Returns
240		///
241		/// A new `TryThunk` instance representing the chained computation.
242		///
243		/// ### Examples
244		///
245		/// ```
246		/// use fp_library::types::*;
247		///
248		/// let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).bind(|x| TryThunk::pure(x * 2));
249		/// assert_eq!(try_thunk.evaluate(), Ok(42));
250		/// ```
251		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		/// Functor map: transforms the result.
265		///
266		/// ### Type Signature
267		///
268		#[document_signature]
269		///
270		/// ### Type Parameters
271		///
272		#[document_type_parameters(
273			"The type of the result of the transformation.",
274			"The type of the transformation function."
275		)]
276		///
277		/// ### Parameters
278		///
279		#[document_parameters("The function to apply to the result of the computation.")]
280		///
281		/// ### Returns
282		///
283		/// A new `TryThunk` instance with the transformed result.
284		///
285		/// ### Examples
286		///
287		/// ```
288		/// use fp_library::types::*;
289		///
290		/// let try_thunk: TryThunk<i32, ()> = TryThunk::pure(21).map(|x| x * 2);
291		/// assert_eq!(try_thunk.evaluate(), Ok(42));
292		/// ```
293		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		/// Map error: transforms the error.
304		///
305		/// ### Type Signature
306		///
307		#[document_signature]
308		///
309		/// ### Type Parameters
310		///
311		#[document_type_parameters(
312			"The type of the new error.",
313			"The type of the transformation function."
314		)]
315		///
316		/// ### Parameters
317		///
318		#[document_parameters("The function to apply to the error.")]
319		///
320		/// ### Returns
321		///
322		/// A new `TryThunk` instance with the transformed error.
323		///
324		/// ### Examples
325		///
326		/// ```
327		/// use fp_library::types::*;
328		///
329		/// let try_thunk: TryThunk<i32, i32> = TryThunk::err(21).map_err(|x| x * 2);
330		/// assert_eq!(try_thunk.evaluate(), Err(42));
331		/// ```
332		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		/// Recovers from an error.
343		///
344		/// ### Type Signature
345		///
346		#[document_signature]
347		///
348		/// ### Type Parameters
349		///
350		#[document_type_parameters("The type of the recovery function.")]
351		///
352		/// ### Parameters
353		///
354		#[document_parameters("The function to apply to the error value.")]
355		///
356		/// ### Returns
357		///
358		/// A new `TryThunk` that attempts to recover from failure.
359		///
360		/// ### Examples
361		///
362		/// ```
363		/// use fp_library::types::*;
364		///
365		/// let try_thunk: TryThunk<i32, &str> = TryThunk::err("error")
366		///     .catch(|_| TryThunk::pure(42));
367		/// assert_eq!(try_thunk.evaluate(), Ok(42));
368		/// ```
369		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		/// Forces evaluation and returns the result.
383		///
384		/// ### Type Signature
385		///
386		#[document_signature]
387		///
388		/// ### Returns
389		///
390		/// The result of the computation.
391		///
392		/// ### Examples
393		///
394		/// ```
395		/// use fp_library::types::*;
396		///
397		/// let try_thunk: TryThunk<i32, ()> = TryThunk::pure(42);
398		/// assert_eq!(try_thunk.evaluate(), Ok(42));
399		/// ```
400		pub fn evaluate(self) -> Result<A, E> {
401			(self.0)()
402		}
403	}
404
405	/// ### Type Parameters
406	///
407	#[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		/// ### Type Signature
420		///
421		#[document_signature]
422		///
423		/// ### Parameters
424		///
425		#[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	/// ### Type Parameters
432	///
433	#[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		/// ### Type Signature
446		///
447		#[document_signature]
448		///
449		/// ### Parameters
450		///
451		#[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	/// ### Type Parameters
458	///
459	#[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		/// ### Type Signature
466		///
467		#[document_signature]
468		///
469		/// ### Parameters
470		///
471		#[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	/// ### Type Parameters
478	///
479	#[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		/// Creates a `TryThunk` from a computation that produces it.
490		///
491		/// ### Type Signature
492		///
493		#[document_signature]
494		///
495		/// ### Type Parameters
496		///
497		#[document_type_parameters("The type of the thunk.")]
498		///
499		/// ### Parameters
500		///
501		#[document_parameters("A thunk that produces the try thunk.")]
502		///
503		/// ### Returns
504		///
505		/// The deferred try thunk.
506		///
507		/// ### Examples
508		///
509		/// ```
510		/// use fp_library::{brands::*, functions::*, types::*, classes::Deferrable};
511		///
512		/// let task: TryThunk<i32, ()> = Deferrable::defer(|| TryThunk::pure(42));
513		/// assert_eq!(task.evaluate(), Ok(42));
514		/// ```
515		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	/// ### Type Parameters
532	///
533	#[document_type_parameters("The error type.")]
534	impl<E: 'static> Functor for TryThunkWithErrBrand<E> {
535		/// Maps a function over the result of a `TryThunk` computation.
536		///
537		/// ### Type Signature
538		///
539		#[document_signature]
540		///
541		/// ### Type Parameters
542		///
543		#[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		///
550		/// ### Parameters
551		///
552		#[document_parameters(
553			"The function to apply to the result of the computation.",
554			"The `TryThunk` instance."
555		)]
556		///
557		/// ### Returns
558		///
559		/// A new `TryThunk` instance with the transformed result.
560		///
561		/// ### Examples
562		///
563		/// ```
564		/// use fp_library::{brands::*, functions::*, types::*};
565		///
566		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
567		/// let mapped = map::<TryThunkWithErrBrand<()>, _, _, _>(|x| x * 2, try_thunk);
568		/// assert_eq!(mapped.evaluate(), Ok(20));
569		/// ```
570		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	/// ### Type Parameters
582	///
583	#[document_type_parameters("The error type.")]
584	impl<E: 'static> Pointed for TryThunkWithErrBrand<E> {
585		/// Wraps a value in a `TryThunk` context.
586		///
587		/// ### Type Signature
588		///
589		#[document_signature]
590		///
591		/// ### Type Parameters
592		///
593		#[document_type_parameters(
594			"The lifetime of the computation.",
595			"The type of the value to wrap."
596		)]
597		///
598		/// ### Parameters
599		///
600		#[document_parameters("The value to wrap.")]
601		///
602		/// ### Returns
603		///
604		/// A new `TryThunk` instance containing the value.
605		///
606		/// ### Examples
607		///
608		/// ```
609		/// use fp_library::{brands::*, functions::*, types::*};
610		///
611		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(42);
612		/// assert_eq!(try_thunk.evaluate(), Ok(42));
613		/// ```
614		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	/// ### Type Parameters
620	///
621	#[document_type_parameters("The error type.")]
622	impl<E: 'static> Lift for TryThunkWithErrBrand<E> {
623		/// Lifts a binary function into the `TryThunk` context.
624		///
625		/// ### Type Signature
626		///
627		#[document_signature]
628		///
629		/// ### Type Parameters
630		///
631		#[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		///
639		/// ### Parameters
640		///
641		#[document_parameters(
642			"The binary function to apply.",
643			"The first `TryThunk`.",
644			"The second `TryThunk`."
645		)]
646		///
647		/// ### Returns
648		///
649		/// A new `TryThunk` instance containing the result of applying the function.
650		///
651		/// ### Examples
652		///
653		/// ```
654		/// use fp_library::{brands::*, functions::*, types::*};
655		///
656		/// let eval1: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
657		/// let eval2: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(20);
658		/// let result = lift2::<TryThunkWithErrBrand<()>, _, _, _, _>(|a, b| a + b, eval1, eval2);
659		/// assert_eq!(result.evaluate(), Ok(30));
660		/// ```
661		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	/// ### Type Parameters
677	///
678	#[document_type_parameters("The error type.")]
679	impl<E: 'static> ApplyFirst for TryThunkWithErrBrand<E> {}
680
681	/// ### Type Parameters
682	///
683	#[document_type_parameters("The error type.")]
684	impl<E: 'static> ApplySecond for TryThunkWithErrBrand<E> {}
685
686	/// ### Type Parameters
687	///
688	#[document_type_parameters("The error type.")]
689	impl<E: 'static> Semiapplicative for TryThunkWithErrBrand<E> {
690		/// Applies a function wrapped in `TryThunk` to a value wrapped in `TryThunk`.
691		///
692		/// ### Type Signature
693		///
694		#[document_signature]
695		///
696		/// ### Type Parameters
697		///
698		#[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		///
705		/// ### Parameters
706		///
707		#[document_parameters(
708			"The `TryThunk` containing the function.",
709			"The `TryThunk` containing the value."
710		)]
711		///
712		/// ### Returns
713		///
714		/// A new `TryThunk` instance containing the result of applying the function.
715		///
716		/// ### Examples
717		///
718		/// ```
719		/// use fp_library::{brands::*, functions::*, types::*};
720		///
721		/// let func: TryThunk<_, ()> = pure::<TryThunkWithErrBrand<()>, _>(cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
722		/// let val: TryThunk<_, ()> = pure::<TryThunkWithErrBrand<()>, _>(21);
723		/// let result = apply::<RcFnBrand, TryThunkWithErrBrand<()>, _, _>(func, val);
724		/// assert_eq!(result.evaluate(), Ok(42));
725		/// ```
726		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)] // Required for move semantics
733					move |a| f(a),
734				)
735			})
736		}
737	}
738
739	/// ### Type Parameters
740	///
741	#[document_type_parameters("The error type.")]
742	impl<E: 'static> Semimonad for TryThunkWithErrBrand<E> {
743		/// Chains `TryThunk` computations.
744		///
745		/// ### Type Signature
746		///
747		#[document_signature]
748		///
749		/// ### Type Parameters
750		///
751		#[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		///
758		/// ### Parameters
759		///
760		#[document_parameters(
761			"The first `TryThunk`.",
762			"The function to apply to the result of the computation."
763		)]
764		///
765		/// ### Returns
766		///
767		/// A new `TryThunk` instance representing the chained computation.
768		///
769		/// ### Examples
770		///
771		/// ```
772		/// use fp_library::{brands::*, functions::*, types::*};
773		///
774		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
775		/// let result = bind::<TryThunkWithErrBrand<()>, _, _, _>(try_thunk, |x| pure::<TryThunkWithErrBrand<()>, _>(x * 2));
776		/// assert_eq!(result.evaluate(), Ok(20));
777		/// ```
778		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	/// ### Type Parameters
790	///
791	#[document_type_parameters("The error type.")]
792	impl<E: 'static> MonadRec for TryThunkWithErrBrand<E> {
793		/// Performs tail-recursive monadic computation.
794		///
795		/// ### Type Signature
796		///
797		#[document_signature]
798		///
799		/// ### Type Parameters
800		///
801		#[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		///
808		/// ### Parameters
809		///
810		#[document_parameters("The step function.", "The initial value.")]
811		///
812		/// ### Returns
813		///
814		/// The result of the computation.
815		///
816		/// ### Examples
817		///
818		/// ```
819		/// use fp_library::{brands::*, classes::*, functions::*, types::*};
820		///
821		/// let result = tail_rec_m::<TryThunkWithErrBrand<()>, _, _, _>(
822		///     |x| pure::<TryThunkWithErrBrand<()>, _>(if x < 1000 { Step::Loop(x + 1) } else { Step::Done(x) }),
823		///     0,
824		/// );
825		/// assert_eq!(result.evaluate(), Ok(1000));
826		/// ```
827		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	/// ### Type Parameters
850	///
851	#[document_type_parameters("The error type.")]
852	impl<E: 'static> Foldable for TryThunkWithErrBrand<E> {
853		/// Folds the `TryThunk` from the right.
854		///
855		/// ### Type Signature
856		///
857		#[document_signature]
858		///
859		/// ### Type Parameters
860		///
861		#[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		///
869		/// ### Parameters
870		///
871		#[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		///
877		/// ### Returns
878		///
879		/// The final accumulator value.
880		///
881		/// ### Examples
882		///
883		/// ```
884		/// use fp_library::{brands::*, functions::*, types::*};
885		///
886		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
887		/// let result = fold_right::<RcFnBrand, TryThunkWithErrBrand<()>, _, _, _>(|a, b| a + b, 5, try_thunk);
888		/// assert_eq!(result, 15);
889		/// ```
890		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		/// Folds the `TryThunk` from the left.
906		///
907		/// ### Type Signature
908		///
909		#[document_signature]
910		///
911		/// ### Type Parameters
912		///
913		#[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		///
921		/// ### Parameters
922		///
923		#[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		///
929		/// ### Returns
930		///
931		/// The final accumulator value.
932		///
933		/// ### Examples
934		///
935		/// ```
936		/// use fp_library::{brands::*, functions::*, types::*};
937		///
938		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
939		/// let result = fold_left::<RcFnBrand, TryThunkWithErrBrand<()>, _, _, _>(|b, a| b + a, 5, try_thunk);
940		/// assert_eq!(result, 15);
941		/// ```
942		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		/// Maps the value to a monoid and returns it.
958		///
959		/// ### Type Signature
960		///
961		#[document_signature]
962		///
963		/// ### Type Parameters
964		///
965		#[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		///
973		/// ### Parameters
974		///
975		#[document_parameters("The mapping function.", "The Thunk to fold.")]
976		///
977		/// ### Returns
978		///
979		/// The monoid value.
980		///
981		/// ### Examples
982		///
983		/// ```
984		/// use fp_library::{brands::*, functions::*, types::*};
985		///
986		/// let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(10);
987		/// let result = fold_map::<RcFnBrand, TryThunkWithErrBrand<()>, _, _, _>(|a| a.to_string(), try_thunk);
988		/// assert_eq!(result, "10");
989		/// ```
990		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	/// ### Type Parameters
1007	///
1008	#[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		/// Combines two `TryThunk`s by combining their results.
1015		///
1016		/// ### Type Signature
1017		///
1018		#[document_signature]
1019		///
1020		/// ### Parameters
1021		///
1022		#[document_parameters("The first `TryThunk`.", "The second `TryThunk`.")]
1023		///
1024		/// ### Returns
1025		///
1026		/// A new `TryThunk` containing the combined result.
1027		///
1028		/// ### Examples
1029		///
1030		/// ```
1031		/// use fp_library::{brands::*, classes::*, functions::*, types::*};
1032		///
1033		/// let t1: TryThunk<String, ()> = pure::<TryThunkWithErrBrand<()>, _>("Hello".to_string());
1034		/// let t2: TryThunk<String, ()> = pure::<TryThunkWithErrBrand<()>, _>(" World".to_string());
1035		/// let t3 = append::<_>(t1, t2);
1036		/// assert_eq!(t3.evaluate(), Ok("Hello World".to_string()));
1037		/// ```
1038		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	/// ### Type Parameters
1051	///
1052	#[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		/// Returns the identity `TryThunk`.
1059		///
1060		/// ### Type Signature
1061		///
1062		#[document_signature]
1063		///
1064		/// ### Returns
1065		///
1066		/// A `TryThunk` producing the identity value of `A`.
1067		///
1068		/// ### Examples
1069		///
1070		/// ```
1071		/// use fp_library::{classes::*, types::*};
1072		///
1073		/// let t: TryThunk<String, ()> = TryThunk::empty();
1074		/// assert_eq!(t.evaluate(), Ok("".to_string()));
1075		/// ```
1076		fn empty() -> Self {
1077			TryThunk::new(|| Ok(Monoid::empty()))
1078		}
1079	}
1080
1081	impl_kind! {
1082		/// HKT branding for the `TryThunk` type.
1083		///
1084		/// The type parameters for `Of` are ordered `E`, then `A` (Error, then Success).
1085		/// This follows the same convention as `ResultBrand`, matching functional
1086		/// programming expectations (like Haskell's `Either e a`) where the success
1087		/// type is the last parameter.
1088		for TryThunkBrand {
1089			type Of<'a, E: 'a, A: 'a>: 'a = TryThunk<'a, A, E>;
1090		}
1091	}
1092
1093	impl Bifunctor for TryThunkBrand {
1094		/// Maps functions over the values in the `TryThunk`.
1095		///
1096		/// This method applies one function to the error value and another to the success value.
1097		///
1098		/// ### Type Signature
1099		///
1100		#[document_signature]
1101		///
1102		/// ### Type Parameters
1103		///
1104		#[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		///
1114		/// ### Parameters
1115		///
1116		#[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		///
1122		/// ### Returns
1123		///
1124		/// A new `TryThunk` containing the mapped values.
1125		///
1126		/// ### Examples
1127		///
1128		/// ```
1129		/// use fp_library::{brands::*, classes::bifunctor::*, functions::*, types::*};
1130		///
1131		/// let x: TryThunk<i32, i32> = TryThunk::pure(5);
1132		/// assert_eq!(bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, x).evaluate(), Ok(10));
1133		///
1134		/// let y: TryThunk<i32, i32> = TryThunk::err(5);
1135		/// assert_eq!(bimap::<TryThunkBrand, _, _, _, _, _, _>(|e| e + 1, |s| s * 2, y).evaluate(), Err(6));
1136		/// ```
1137		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	/// ### Type Parameters
1161	///
1162	#[document_type_parameters("The success type.")]
1163	impl<A: 'static> Functor for TryThunkWithOkBrand<A> {
1164		/// Maps a function over the error value in the `TryThunk`.
1165		///
1166		/// ### Type Signature
1167		///
1168		#[document_signature]
1169		///
1170		/// ### Type Parameters
1171		///
1172		#[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		///
1179		/// ### Parameters
1180		///
1181		#[document_parameters("The function to apply to the error.", "The `TryThunk` instance.")]
1182		///
1183		/// ### Returns
1184		///
1185		/// A new `TryThunk` instance with the transformed error.
1186		///
1187		/// ### Examples
1188		///
1189		/// ```
1190		/// use fp_library::{brands::*, functions::*, types::*};
1191		///
1192		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1193		/// let mapped = map::<TryThunkWithOkBrand<i32>, _, _, _>(|x| x * 2, try_thunk);
1194		/// assert_eq!(mapped.evaluate(), Err(20));
1195		/// ```
1196		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	/// ### Type Parameters
1208	///
1209	#[document_type_parameters("The success type.")]
1210	impl<A: 'static> Pointed for TryThunkWithOkBrand<A> {
1211		/// Wraps a value in a `TryThunk` context (as error).
1212		///
1213		/// ### Type Signature
1214		///
1215		#[document_signature]
1216		///
1217		/// ### Type Parameters
1218		///
1219		#[document_type_parameters(
1220			"The lifetime of the computation.",
1221			"The type of the value to wrap."
1222		)]
1223		///
1224		/// ### Parameters
1225		///
1226		#[document_parameters("The value to wrap.")]
1227		///
1228		/// ### Returns
1229		///
1230		/// A new `TryThunk` instance containing the value as an error.
1231		///
1232		/// ### Examples
1233		///
1234		/// ```
1235		/// use fp_library::{brands::*, functions::*, types::*};
1236		///
1237		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(42);
1238		/// assert_eq!(try_thunk.evaluate(), Err(42));
1239		/// ```
1240		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	/// ### Type Parameters
1246	///
1247	#[document_type_parameters("The success type.")]
1248	impl<A: 'static> Lift for TryThunkWithOkBrand<A> {
1249		/// Lifts a binary function into the `TryThunk` context (over error).
1250		///
1251		/// ### Type Signature
1252		///
1253		#[document_signature]
1254		///
1255		/// ### Type Parameters
1256		///
1257		#[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		///
1265		/// ### Parameters
1266		///
1267		#[document_parameters(
1268			"The binary function to apply to the errors.",
1269			"The first `TryThunk`.",
1270			"The second `TryThunk`."
1271		)]
1272		///
1273		/// ### Returns
1274		///
1275		/// A new `TryThunk` instance containing the result of applying the function to the errors.
1276		///
1277		/// ### Examples
1278		///
1279		/// ```
1280		/// use fp_library::{brands::*, functions::*, types::*};
1281		///
1282		/// let eval1: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1283		/// let eval2: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(20);
1284		/// let result = lift2::<TryThunkWithOkBrand<i32>, _, _, _, _>(|a, b| a + b, eval1, eval2);
1285		/// assert_eq!(result.evaluate(), Err(30));
1286		/// ```
1287		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	/// ### Type Parameters
1307	///
1308	#[document_type_parameters("The success type.")]
1309	impl<A: 'static> ApplyFirst for TryThunkWithOkBrand<A> {}
1310
1311	/// ### Type Parameters
1312	///
1313	#[document_type_parameters("The success type.")]
1314	impl<A: 'static> ApplySecond for TryThunkWithOkBrand<A> {}
1315
1316	/// ### Type Parameters
1317	///
1318	#[document_type_parameters("The success type.")]
1319	impl<A: 'static> Semiapplicative for TryThunkWithOkBrand<A> {
1320		/// Applies a function wrapped in `TryThunk` (as error) to a value wrapped in `TryThunk` (as error).
1321		///
1322		/// ### Type Signature
1323		///
1324		#[document_signature]
1325		///
1326		/// ### Type Parameters
1327		///
1328		#[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		///
1335		/// ### Parameters
1336		///
1337		#[document_parameters(
1338			"The `TryThunk` containing the function (in Err).",
1339			"The `TryThunk` containing the value (in Err)."
1340		)]
1341		///
1342		/// ### Returns
1343		///
1344		/// A new `TryThunk` instance containing the result of applying the function.
1345		///
1346		/// ### Examples
1347		///
1348		/// ```
1349		/// use fp_library::{brands::*, functions::*, types::*};
1350		///
1351		/// let func: TryThunk<i32, _> = pure::<TryThunkWithOkBrand<i32>, _>(cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
1352		/// let val: TryThunk<i32, _> = pure::<TryThunkWithOkBrand<i32>, _>(21);
1353		/// let result = apply::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _>(func, val);
1354		/// assert_eq!(result.evaluate(), Err(42));
1355		/// ```
1356		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	/// ### Type Parameters
1369	///
1370	#[document_type_parameters("The success type.")]
1371	impl<A: 'static> Semimonad for TryThunkWithOkBrand<A> {
1372		/// Chains `TryThunk` computations (over error).
1373		///
1374		/// ### Type Signature
1375		///
1376		#[document_signature]
1377		///
1378		/// ### Type Parameters
1379		///
1380		#[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		///
1387		/// ### Parameters
1388		///
1389		#[document_parameters(
1390			"The first `TryThunk`.",
1391			"The function to apply to the error result of the computation."
1392		)]
1393		///
1394		/// ### Returns
1395		///
1396		/// A new `TryThunk` instance representing the chained computation.
1397		///
1398		/// ### Examples
1399		///
1400		/// ```
1401		/// use fp_library::{brands::*, functions::*, types::*};
1402		///
1403		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1404		/// let result = bind::<TryThunkWithOkBrand<i32>, _, _, _>(try_thunk, |x| pure::<TryThunkWithOkBrand<i32>, _>(x * 2));
1405		/// assert_eq!(result.evaluate(), Err(20));
1406		/// ```
1407		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	/// ### Type Parameters
1422	///
1423	#[document_type_parameters("The success type.")]
1424	impl<A: 'static> Foldable for TryThunkWithOkBrand<A> {
1425		/// Folds the `TryThunk` from the right (over error).
1426		///
1427		/// ### Type Signature
1428		///
1429		#[document_signature]
1430		///
1431		/// ### Type Parameters
1432		///
1433		#[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		///
1441		/// ### Parameters
1442		///
1443		#[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		///
1449		/// ### Returns
1450		///
1451		/// The final accumulator value.
1452		///
1453		/// ### Examples
1454		///
1455		/// ```
1456		/// use fp_library::{brands::*, functions::*, types::*};
1457		///
1458		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1459		/// let result = fold_right::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _, _>(|a, b| a + b, 5, try_thunk);
1460		/// assert_eq!(result, 15);
1461		/// ```
1462		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		/// Folds the `TryThunk` from the left (over error).
1478		///
1479		/// ### Type Signature
1480		///
1481		#[document_signature]
1482		///
1483		/// ### Type Parameters
1484		///
1485		#[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		///
1493		/// ### Parameters
1494		///
1495		#[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		///
1501		/// ### Returns
1502		///
1503		/// The final accumulator value.
1504		///
1505		/// ### Examples
1506		///
1507		/// ```
1508		/// use fp_library::{brands::*, functions::*, types::*};
1509		///
1510		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1511		/// let result = fold_left::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _, _>(|b, a| b + a, 5, try_thunk);
1512		/// assert_eq!(result, 15);
1513		/// ```
1514		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		/// Maps the value to a monoid and returns it (over error).
1530		///
1531		/// ### Type Signature
1532		///
1533		#[document_signature]
1534		///
1535		/// ### Type Parameters
1536		///
1537		#[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		///
1545		/// ### Parameters
1546		///
1547		#[document_parameters("The mapping function.", "The Thunk to fold.")]
1548		///
1549		/// ### Returns
1550		///
1551		/// The monoid value.
1552		///
1553		/// ### Examples
1554		///
1555		/// ```
1556		/// use fp_library::{brands::*, functions::*, types::*};
1557		///
1558		/// let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(10);
1559		/// let result = fold_map::<RcFnBrand, TryThunkWithOkBrand<i32>, _, _, _>(|a| a.to_string(), try_thunk);
1560		/// assert_eq!(result, "10");
1561		/// ```
1562		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	/// Tests success path.
1587	///
1588	/// Verifies that `TryThunk::pure` creates a successful computation.
1589	#[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	/// Tests failure path.
1596	///
1597	/// Verifies that `TryThunk::err` creates a failed computation.
1598	#[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	/// Tests `TryThunk::map`.
1605	///
1606	/// Verifies that `map` transforms the success value.
1607	#[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	/// Tests `TryThunk::map_err`.
1614	///
1615	/// Verifies that `map_err` transforms the error value.
1616	#[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	/// Tests `TryThunk::bind`.
1623	///
1624	/// Verifies that `bind` chains computations.
1625	#[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	/// Tests borrowing in TryThunk.
1632	///
1633	/// Verifies that `TryThunk` can capture references.
1634	#[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	/// Tests `TryThunk::bind` failure propagation.
1642	///
1643	/// Verifies that if the first computation fails, the second one is not executed.
1644	#[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	/// Tests `TryThunk::map` failure propagation.
1651	///
1652	/// Verifies that `map` is not executed if the computation fails.
1653	#[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	/// Tests `TryThunk::map_err` success propagation.
1660	///
1661	/// Verifies that `map_err` is not executed if the computation succeeds.
1662	#[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	/// Tests `From<Lazy>`.
1669	#[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	/// Tests `From<TryLazy>`.
1678	#[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	/// Tests `Thunk::into_try`.
1687	///
1688	/// Verifies that `From<Thunk>` converts a `Thunk` into a `TryThunk` that succeeds.
1689	#[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	/// Tests `TryThunk::defer`.
1697	#[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	/// Tests `TryThunk::catch`.
1704	///
1705	/// Verifies that `catch` recovers from failure.
1706	#[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	/// Tests `TryThunkWithErrBrand` (Functor over Success).
1713	#[test]
1714	fn test_try_thunk_with_err_brand() {
1715		use crate::{brands::*, functions::*};
1716
1717		// Functor (map over success)
1718		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		// Pointed (pure -> ok)
1723		let try_thunk: TryThunk<i32, ()> = pure::<TryThunkWithErrBrand<()>, _>(42);
1724		assert_eq!(try_thunk.evaluate(), Ok(42));
1725
1726		// Semimonad (bind over success)
1727		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		// Foldable (fold over success)
1734		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	/// Tests `Bifunctor` for `TryThunkBrand`.
1744	#[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	/// Tests `TryThunkWithOkBrand` (Functor over Error).
1762	#[test]
1763	fn test_try_thunk_with_ok_brand() {
1764		use crate::{brands::*, functions::*};
1765
1766		// Functor (map over error)
1767		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		// Pointed (pure -> err)
1772		let try_thunk: TryThunk<i32, i32> = pure::<TryThunkWithOkBrand<i32>, _>(42);
1773		assert_eq!(try_thunk.evaluate(), Err(42));
1774
1775		// Semimonad (bind over error)
1776		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		// Foldable (fold over error)
1783		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}