Skip to main content

fp_library/types/
option.rs

1//! Functional programming trait implementations for the standard library [`Option`] type.
2//!
3//! Extends `Option` with [`Functor`](crate::classes::Functor), [`Monad`](crate::classes::semimonad::Semimonad), [`Foldable`](crate::classes::Foldable), [`Traversable`](crate::classes::Traversable), [`Filterable`](crate::classes::Filterable), and [`Witherable`](crate::classes::Witherable) instances.
4
5#[fp_macros::document_module]
6mod inner {
7	use {
8		crate::{
9			Apply,
10			brands::OptionBrand,
11			classes::{
12				Alt,
13				Applicative,
14				ApplyFirst,
15				ApplySecond,
16				CloneableFn,
17				Compactable,
18				Filterable,
19				Foldable,
20				Functor,
21				Lift,
22				MonadRec,
23				Monoid,
24				Plus,
25				Pointed,
26				Semiapplicative,
27				Semimonad,
28				Traversable,
29				Witherable,
30				foldable_with_index::FoldableWithIndex,
31				functor_with_index::FunctorWithIndex,
32				traversable_with_index::TraversableWithIndex,
33				with_index::WithIndex,
34			},
35			impl_kind,
36			kinds::*,
37		},
38		core::ops::ControlFlow,
39		fp_macros::*,
40	};
41
42	impl_kind! {
43		for OptionBrand {
44			type Of<'a, A: 'a>: 'a = Option<A>;
45		}
46	}
47
48	impl Functor for OptionBrand {
49		/// Maps a function over the value in the option.
50		///
51		/// This method applies a function to the value inside the option, producing a new option with the transformed value. If the option is `None`, it returns `None`.
52		#[document_signature]
53		///
54		#[document_type_parameters(
55			"The lifetime of the value.",
56			"The type of the value inside the option.",
57			"The type of the result of applying the function."
58		)]
59		///
60		#[document_parameters("The function to apply to the value.", "The option to map over.")]
61		///
62		#[document_returns(
63			"A new option containing the result of applying the function, or `None`."
64		)]
65		///
66		#[document_examples]
67		///
68		/// ```
69		/// use fp_library::{
70		/// 	brands::*,
71		/// 	functions::*,
72		/// };
73		///
74		/// let x = Some(5);
75		/// let y = map::<OptionBrand, _, _>(|i| i * 2, x);
76		/// assert_eq!(y, Some(10));
77		/// ```
78		fn map<'a, A: 'a, B: 'a>(
79			func: impl Fn(A) -> B + 'a,
80			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
81		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
82			fa.map(func)
83		}
84	}
85
86	impl Lift for OptionBrand {
87		/// Lifts a binary function into the option context.
88		///
89		/// This method lifts a binary function to operate on values within the option context.
90		#[document_signature]
91		///
92		#[document_type_parameters(
93			"The lifetime of the values.",
94			"The type of the first option's value.",
95			"The type of the second option's value.",
96			"The return type of the function."
97		)]
98		///
99		#[document_parameters(
100			"The binary function to apply.",
101			"The first option.",
102			"The second option."
103		)]
104		///
105		#[document_returns("`Some(f(a, b))` if both options are `Some`, otherwise `None`.")]
106		#[document_examples]
107		///
108		/// ```
109		/// use fp_library::{
110		/// 	brands::*,
111		/// 	functions::*,
112		/// };
113		///
114		/// let x = Some(1);
115		/// let y = Some(2);
116		/// let z = lift2::<OptionBrand, _, _, _>(|a, b| a + b, x, y);
117		/// assert_eq!(z, Some(3));
118		/// ```
119		fn lift2<'a, A, B, C>(
120			func: impl Fn(A, B) -> C + 'a,
121			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
122			fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
123		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
124		where
125			A: 'a,
126			B: 'a,
127			C: 'a, {
128			fa.zip(fb).map(|(a, b)| func(a, b))
129		}
130	}
131
132	impl Pointed for OptionBrand {
133		/// Wraps a value in an option.
134		///
135		/// This method wraps a value in an option context.
136		#[document_signature]
137		///
138		#[document_type_parameters("The lifetime of the value.", "The type of the value to wrap.")]
139		///
140		#[document_parameters("The value to wrap.")]
141		///
142		#[document_returns("`Some(a)`.")]
143		///
144		#[document_examples]
145		///
146		/// ```
147		/// use fp_library::{
148		/// 	brands::OptionBrand,
149		/// 	functions::*,
150		/// };
151		///
152		/// let x = pure::<OptionBrand, _>(5);
153		/// assert_eq!(x, Some(5));
154		/// ```
155		fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
156			Some(a)
157		}
158	}
159
160	impl ApplyFirst for OptionBrand {}
161	impl ApplySecond for OptionBrand {}
162
163	impl Semiapplicative for OptionBrand {
164		/// Applies a wrapped function to a wrapped value.
165		///
166		/// This method applies a function wrapped in an option to a value wrapped in an option.
167		#[document_signature]
168		///
169		#[document_type_parameters(
170			"The lifetime of the values.",
171			"The brand of the cloneable function wrapper.",
172			"The type of the input value.",
173			"The type of the output value."
174		)]
175		///
176		#[document_parameters(
177			"The option containing the function.",
178			"The option containing the value."
179		)]
180		///
181		#[document_returns("`Some(f(a))` if both are `Some`, otherwise `None`.")]
182		#[document_examples]
183		///
184		/// ```
185		/// use fp_library::{
186		/// 	brands::*,
187		/// 	classes::*,
188		/// 	functions::*,
189		/// };
190		///
191		/// let f = Some(cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
192		/// let x = Some(5);
193		/// let y = apply::<RcFnBrand, OptionBrand, _, _>(f, x);
194		/// assert_eq!(y, Some(10));
195		/// ```
196		fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
197			ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
198			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
199		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
200			match (ff, fa) {
201				(Some(f), Some(a)) => Some(f(a)),
202				_ => None,
203			}
204		}
205	}
206
207	impl Semimonad for OptionBrand {
208		/// Chains option computations.
209		///
210		/// This method chains two option computations, where the second computation depends on the result of the first.
211		#[document_signature]
212		///
213		#[document_type_parameters(
214			"The lifetime of the values.",
215			"The type of the result of the first computation.",
216			"The type of the result of the second computation."
217		)]
218		///
219		#[document_parameters(
220			"The first option.",
221			"The function to apply to the value inside the option."
222		)]
223		///
224		#[document_returns(
225			"The result of applying `f` to the value if `ma` is `Some`, otherwise `None`."
226		)]
227		#[document_examples]
228		///
229		/// ```
230		/// use fp_library::{
231		/// 	brands::OptionBrand,
232		/// 	functions::*,
233		/// };
234		///
235		/// let x = Some(5);
236		/// let y = bind::<OptionBrand, _, _>(x, |i| Some(i * 2));
237		/// assert_eq!(y, Some(10));
238		/// ```
239		fn bind<'a, A: 'a, B: 'a>(
240			ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
241			func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
242		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
243			ma.and_then(func)
244		}
245	}
246
247	impl Alt for OptionBrand {
248		/// Chooses between two options.
249		///
250		/// Returns the first `Some` value, or `None` if both are `None`.
251		#[document_signature]
252		///
253		#[document_type_parameters("The lifetime of the values.", "The type of the value.")]
254		///
255		#[document_parameters("The first option.", "The second option.")]
256		///
257		#[document_returns("The first `Some` value, or `None`.")]
258		#[document_examples]
259		///
260		/// ```
261		/// use fp_library::{
262		/// 	brands::*,
263		/// 	classes::*,
264		/// 	functions::*,
265		/// };
266		///
267		/// assert_eq!(alt::<OptionBrand, _>(None, Some(5)), Some(5));
268		/// assert_eq!(alt::<OptionBrand, _>(Some(3), Some(5)), Some(3));
269		/// assert_eq!(alt::<OptionBrand, _>(None::<i32>, None), None);
270		/// ```
271		fn alt<'a, A: 'a>(
272			fa1: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
273			fa2: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
274		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
275			fa1.or(fa2)
276		}
277	}
278
279	impl Plus for OptionBrand {
280		/// Returns `None`, the identity element for [`alt`](Alt::alt).
281		#[document_signature]
282		///
283		#[document_type_parameters("The lifetime of the value.", "The type of the value.")]
284		///
285		#[document_returns("`None`.")]
286		#[document_examples]
287		///
288		/// ```
289		/// use fp_library::{
290		/// 	brands::*,
291		/// 	functions::*,
292		/// };
293		///
294		/// let x: Option<i32> = plus_empty::<OptionBrand, i32>();
295		/// assert_eq!(x, None);
296		/// ```
297		fn empty<'a, A: 'a>() -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
298			None
299		}
300	}
301
302	impl Foldable for OptionBrand {
303		/// Folds the option from the right.
304		///
305		/// This method performs a right-associative fold of the option. If the option is `Some(a)`, it applies the function to `a` and the initial value. If `None`, it returns the initial value.
306		#[document_signature]
307		///
308		#[document_type_parameters(
309			"The lifetime of the values.",
310			"The brand of the cloneable function to use.",
311			"The type of the elements in the structure.",
312			"The type of the accumulator."
313		)]
314		///
315		#[document_parameters("The folding function.", "The initial value.", "The option to fold.")]
316		///
317		#[document_returns("`func(a, initial)` if `fa` is `Some(a)`, otherwise `initial`.")]
318		///
319		#[document_examples]
320		///
321		/// ```
322		/// use fp_library::{
323		/// 	brands::*,
324		/// 	functions::*,
325		/// };
326		///
327		/// let x = Some(5);
328		/// let y = fold_right::<RcFnBrand, OptionBrand, _, _>(|a, b| a + b, 10, x);
329		/// assert_eq!(y, 15);
330		/// ```
331		fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
332			func: impl Fn(A, B) -> B + 'a,
333			initial: B,
334			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
335		) -> B
336		where
337			FnBrand: CloneableFn + 'a, {
338			match fa {
339				Some(a) => func(a, initial),
340				None => initial,
341			}
342		}
343
344		/// Folds the option from the left.
345		///
346		/// This method performs a left-associative fold of the option. If the option is `Some(a)`, it applies the function to the initial value and `a`. If `None`, it returns the initial value.
347		#[document_signature]
348		///
349		#[document_type_parameters(
350			"The lifetime of the values.",
351			"The brand of the cloneable function to use.",
352			"The type of the elements in the structure.",
353			"The type of the accumulator."
354		)]
355		///
356		#[document_parameters(
357			"The function to apply to the accumulator and each element.",
358			"The initial value of the accumulator.",
359			"The option to fold."
360		)]
361		///
362		#[document_returns("`f(initial, a)` if `fa` is `Some(a)`, otherwise `initial`.")]
363		#[document_examples]
364		///
365		/// ```
366		/// use fp_library::{
367		/// 	brands::*,
368		/// 	functions::*,
369		/// };
370		///
371		/// let x = Some(5);
372		/// let y = fold_left::<RcFnBrand, OptionBrand, _, _>(|b, a| b + a, 10, x);
373		/// assert_eq!(y, 15);
374		/// ```
375		fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
376			func: impl Fn(B, A) -> B + 'a,
377			initial: B,
378			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
379		) -> B
380		where
381			FnBrand: CloneableFn + 'a, {
382			match fa {
383				Some(a) => func(initial, a),
384				None => initial,
385			}
386		}
387
388		/// Maps the value to a monoid and returns it, or returns empty.
389		///
390		/// This method maps the element of the option to a monoid. If the option is `None`, it returns the monoid's identity element.
391		#[document_signature]
392		///
393		#[document_type_parameters(
394			"The lifetime of the values.",
395			"The brand of the cloneable function to use.",
396			"The type of the elements in the structure.",
397			"The type of the monoid."
398		)]
399		///
400		#[document_parameters("The mapping function.", "The option to fold.")]
401		///
402		#[document_returns("`func(a)` if `fa` is `Some(a)`, otherwise `M::empty()`.")]
403		///
404		#[document_examples]
405		///
406		/// ```
407		/// use fp_library::{
408		/// 	brands::*,
409		/// 	functions::*,
410		/// };
411		///
412		/// let x = Some(5);
413		/// let y = fold_map::<RcFnBrand, OptionBrand, _, _>(|a: i32| a.to_string(), x);
414		/// assert_eq!(y, "5".to_string());
415		/// ```
416		fn fold_map<'a, FnBrand, A: 'a + Clone, M>(
417			func: impl Fn(A) -> M + 'a,
418			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
419		) -> M
420		where
421			M: Monoid + 'a,
422			FnBrand: CloneableFn + 'a, {
423			match fa {
424				Some(a) => func(a),
425				None => M::empty(),
426			}
427		}
428	}
429
430	impl Traversable for OptionBrand {
431		/// Traverses the option with an applicative function.
432		///
433		/// This method maps the element of the option to a computation, evaluates it, and wraps the result in the applicative context. If `None`, it returns `pure(None)`.
434		#[document_signature]
435		///
436		#[document_type_parameters(
437			"The lifetime of the values.",
438			"The type of the elements in the traversable structure.",
439			"The type of the elements in the resulting traversable structure.",
440			"The applicative context."
441		)]
442		///
443		#[document_parameters(
444			"The function to apply to each element, returning a value in an applicative context.",
445			"The option to traverse."
446		)]
447		///
448		#[document_returns("The option wrapped in the applicative context.")]
449		#[document_examples]
450		///
451		/// ```
452		/// use fp_library::{
453		/// 	brands::OptionBrand,
454		/// 	functions::*,
455		/// };
456		///
457		/// let x = Some(5);
458		/// let y = traverse::<OptionBrand, _, _, OptionBrand>(|a| Some(a * 2), x);
459		/// assert_eq!(y, Some(Some(10)));
460		/// ```
461		fn traverse<'a, A: 'a + Clone, B: 'a + Clone, F: Applicative>(
462			func: impl Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
463			ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
464		) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
465		where
466			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone, {
467			match ta {
468				Some(a) => F::map(|b| Some(b), func(a)),
469				None => F::pure(None),
470			}
471		}
472
473		/// Sequences an option of applicative.
474		///
475		/// This method evaluates the computation inside the option and wraps the result in the applicative context. If `None`, it returns `pure(None)`.
476		#[document_signature]
477		///
478		#[document_type_parameters(
479			"The lifetime of the values.",
480			"The type of the elements in the traversable structure.",
481			"The applicative context."
482		)]
483		///
484		#[document_parameters("The option containing the applicative value.")]
485		///
486		#[document_returns("The result of the traversal.")]
487		///
488		/// # Returns
489		///
490		/// The option wrapped in the applicative context.
491		#[document_examples]
492		///
493		/// ```
494		/// use fp_library::{
495		/// 	brands::OptionBrand,
496		/// 	functions::*,
497		/// };
498		///
499		/// let x = Some(Some(5));
500		/// let y = sequence::<OptionBrand, _, OptionBrand>(x);
501		/// assert_eq!(y, Some(Some(5)));
502		/// ```
503		fn sequence<'a, A: 'a + Clone, F: Applicative>(
504			ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
505		) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
506		where
507			Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
508			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone, {
509			match ta {
510				Some(fa) => F::map(|a| Some(a), fa),
511				None => F::pure(None),
512			}
513		}
514	}
515
516	impl WithIndex for OptionBrand {
517		type Index = ();
518	}
519
520	impl FunctorWithIndex for OptionBrand {
521		/// Maps a function over the value in the option, providing the index `()`.
522		#[document_signature]
523		#[document_type_parameters(
524			"The lifetime of the value.",
525			"The type of the value inside the option.",
526			"The type of the result of applying the function."
527		)]
528		#[document_parameters(
529			"The function to apply to the value and its index.",
530			"The option to map over."
531		)]
532		#[document_returns(
533			"A new option containing the result of applying the function, or `None`."
534		)]
535		#[document_examples]
536		///
537		/// ```
538		/// use fp_library::{
539		/// 	brands::OptionBrand,
540		/// 	classes::functor_with_index::FunctorWithIndex,
541		/// 	functions::*,
542		/// };
543		/// let x = Some(5);
544		/// let y = <OptionBrand as FunctorWithIndex>::map_with_index(|_, i| i * 2, x);
545		/// assert_eq!(y, Some(10));
546		/// ```
547		fn map_with_index<'a, A: 'a, B: 'a>(
548			f: impl Fn((), A) -> B + 'a,
549			fa: Option<A>,
550		) -> Option<B> {
551			fa.map(|a| f((), a))
552		}
553	}
554
555	impl FoldableWithIndex for OptionBrand {
556		/// Folds the option using a monoid, providing the index `()`.
557		#[document_signature]
558		#[document_type_parameters(
559			"The lifetime of the value.",
560			"The type of the value inside the option.",
561			"The monoid type."
562		)]
563		#[document_parameters(
564			"The function to apply to the value and its index.",
565			"The option to fold."
566		)]
567		#[document_returns("The monoid value.")]
568		#[document_examples]
569		///
570		/// ```
571		/// use fp_library::{
572		/// 	brands::OptionBrand,
573		/// 	classes::foldable_with_index::FoldableWithIndex,
574		/// 	functions::*,
575		/// };
576		/// let x = Some(5);
577		/// let y = <OptionBrand as FoldableWithIndex>::fold_map_with_index(|_, i: i32| i.to_string(), x);
578		/// assert_eq!(y, "5".to_string());
579		/// ```
580		fn fold_map_with_index<'a, A: 'a + Clone, R: Monoid>(
581			f: impl Fn((), A) -> R + 'a,
582			fa: Option<A>,
583		) -> R {
584			match fa {
585				Some(a) => f((), a),
586				None => R::empty(),
587			}
588		}
589	}
590
591	impl TraversableWithIndex for OptionBrand {
592		/// Traverses the option with an applicative function, providing the index `()`.
593		#[document_signature]
594		#[document_type_parameters(
595			"The lifetime of the value.",
596			"The type of the value inside the option.",
597			"The type of the result.",
598			"The applicative context."
599		)]
600		#[document_parameters(
601			"The function to apply to the value and its index, returning a value in an applicative context.",
602			"The option to traverse."
603		)]
604		#[document_returns("The option wrapped in the applicative context.")]
605		#[document_examples]
606		///
607		/// ```
608		/// use fp_library::{
609		/// 	brands::OptionBrand,
610		/// 	classes::traversable_with_index::TraversableWithIndex,
611		/// 	functions::*,
612		/// };
613		/// let x = Some(5);
614		/// let y = <OptionBrand as TraversableWithIndex>::traverse_with_index::<i32, i32, OptionBrand>(
615		/// 	|_, i| Some(i * 2),
616		/// 	x,
617		/// );
618		/// assert_eq!(y, Some(Some(10)));
619		/// ```
620		fn traverse_with_index<'a, A: 'a, B: 'a + Clone, M: Applicative>(
621			f: impl Fn((), A) -> M::Of<'a, B> + 'a,
622			ta: Option<A>,
623		) -> M::Of<'a, Option<B>> {
624			match ta {
625				Some(a) => M::map(|b| Some(b), f((), a)),
626				None => M::pure(None),
627			}
628		}
629	}
630
631	impl Compactable for OptionBrand {
632		/// Compacts a nested option.
633		///
634		/// This method flattens a nested option.
635		#[document_signature]
636		///
637		#[document_type_parameters("The lifetime of the values.", "The type of the elements.")]
638		///
639		#[document_parameters("The nested option.")]
640		///
641		#[document_returns("The flattened option.")]
642		///
643		#[document_examples]
644		///
645		/// ```
646		/// use fp_library::{
647		/// 	brands::OptionBrand,
648		/// 	functions::*,
649		/// };
650		///
651		/// let x = Some(Some(5));
652		/// let y = compact::<OptionBrand, _>(x);
653		/// assert_eq!(y, Some(5));
654		/// ```
655		fn compact<'a, A: 'a>(
656			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
657			'a,
658			Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
659		>)
660		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
661			fa.flatten()
662		}
663
664		/// Separates an option of result.
665		///
666		/// This method separates an option of result into a pair of options.
667		#[document_signature]
668		///
669		#[document_type_parameters(
670			"The lifetime of the values.",
671			"The type of the error value.",
672			"The type of the success value."
673		)]
674		///
675		#[document_parameters("The option of result.")]
676		///
677		#[document_returns("A pair of options.")]
678		///
679		#[document_examples]
680		///
681		/// ```
682		/// use fp_library::{
683		/// 	brands::*,
684		/// 	functions::*,
685		/// };
686		///
687		/// let x: Option<Result<i32, &str>> = Some(Ok(5));
688		/// let (errs, oks) = separate::<OptionBrand, _, _>(x);
689		/// assert_eq!(oks, Some(5));
690		/// assert_eq!(errs, None);
691		/// ```
692		fn separate<'a, E: 'a, O: 'a>(
693			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
694		) -> (
695			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
696			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
697		) {
698			match fa {
699				Some(Ok(o)) => (None, Some(o)),
700				Some(Err(e)) => (Some(e), None),
701				None => (None, None),
702			}
703		}
704	}
705
706	impl Filterable for OptionBrand {
707		/// Partitions an option based on a function that returns a result.
708		///
709		/// This method partitions an option based on a function that returns a result.
710		#[document_signature]
711		///
712		#[document_type_parameters(
713			"The lifetime of the values.",
714			"The type of the input value.",
715			"The type of the error value.",
716			"The type of the success value."
717		)]
718		///
719		#[document_parameters("The function to apply.", "The option to partition.")]
720		///
721		#[document_returns("A pair of options.")]
722		///
723		#[document_examples]
724		///
725		/// ```
726		/// use fp_library::{
727		/// 	brands::*,
728		/// 	functions::*,
729		/// };
730		///
731		/// let x = Some(5);
732		/// let (errs, oks) =
733		/// 	partition_map::<OptionBrand, _, _, _>(|a| if a > 2 { Ok(a) } else { Err(a) }, x);
734		/// assert_eq!(oks, Some(5));
735		/// assert_eq!(errs, None);
736		/// ```
737		fn partition_map<'a, A: 'a, E: 'a, O: 'a>(
738			func: impl Fn(A) -> Result<O, E> + 'a,
739			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
740		) -> (
741			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
742			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
743		) {
744			match fa {
745				Some(a) => match func(a) {
746					Ok(o) => (None, Some(o)),
747					Err(e) => (Some(e), None),
748				},
749				None => (None, None),
750			}
751		}
752
753		/// Partitions an option based on a predicate.
754		///
755		/// This method partitions an option based on a predicate.
756		#[document_signature]
757		///
758		#[document_type_parameters("The lifetime of the values.", "The type of the elements.")]
759		///
760		#[document_parameters("The predicate.", "The option to partition.")]
761		///
762		#[document_returns("A pair of options.")]
763		///
764		#[document_examples]
765		///
766		/// ```
767		/// use fp_library::{
768		/// 	brands::*,
769		/// 	functions::*,
770		/// };
771		///
772		/// let x = Some(5);
773		/// let (not_satisfied, satisfied) = partition::<OptionBrand, _>(|a| a > 2, x);
774		/// assert_eq!(satisfied, Some(5));
775		/// assert_eq!(not_satisfied, None);
776		/// ```
777		fn partition<'a, A: 'a + Clone>(
778			func: impl Fn(A) -> bool + 'a,
779			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
780		) -> (
781			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
782			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
783		) {
784			match fa {
785				Some(a) =>
786					if func(a.clone()) {
787						(None, Some(a))
788					} else {
789						(Some(a), None)
790					},
791				None => (None, None),
792			}
793		}
794
795		/// Maps a function over an option and filters out `None` results.
796		///
797		/// This method maps a function over an option and filters out `None` results.
798		#[document_signature]
799		///
800		#[document_type_parameters(
801			"The lifetime of the values.",
802			"The type of the input value.",
803			"The type of the result of applying the function."
804		)]
805		///
806		#[document_parameters("The function to apply.", "The option to filter and map.")]
807		///
808		#[document_returns("The filtered and mapped option.")]
809		///
810		#[document_examples]
811		///
812		/// ```
813		/// use fp_library::{
814		/// 	brands::OptionBrand,
815		/// 	functions::*,
816		/// };
817		///
818		/// let x = Some(5);
819		/// let y = filter_map::<OptionBrand, _, _>(|a| if a > 2 { Some(a * 2) } else { None }, x);
820		/// assert_eq!(y, Some(10));
821		/// ```
822		fn filter_map<'a, A: 'a, B: 'a>(
823			func: impl Fn(A) -> Option<B> + 'a,
824			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
825		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
826			fa.and_then(func)
827		}
828
829		/// Filters an option based on a predicate.
830		///
831		/// This method filters an option based on a predicate.
832		#[document_signature]
833		///
834		#[document_type_parameters("The lifetime of the values.", "The type of the elements.")]
835		///
836		#[document_parameters("The predicate.", "The option to filter.")]
837		///
838		#[document_returns("The filtered option.")]
839		///
840		#[document_examples]
841		///
842		/// ```
843		/// use fp_library::{
844		/// 	brands::OptionBrand,
845		/// 	functions::*,
846		/// };
847		///
848		/// let x = Some(5);
849		/// let y = filter::<OptionBrand, _>(|a| a > 2, x);
850		/// assert_eq!(y, Some(5));
851		/// ```
852		fn filter<'a, A: 'a + Clone>(
853			func: impl Fn(A) -> bool + 'a,
854			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
855		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
856			fa.filter(|a| func(a.clone()))
857		}
858	}
859
860	impl Witherable for OptionBrand {
861		/// Partitions an option based on a function that returns a result in an applicative context.
862		///
863		/// This method partitions an option based on a function that returns a result in an applicative context.
864		#[document_signature]
865		///
866		#[document_type_parameters(
867			"The lifetime of the values.",
868			"The applicative context.",
869			"The type of the elements in the input structure.",
870			"The type of the error values.",
871			"The type of the success values."
872		)]
873		///
874		#[document_parameters(
875			"The function to apply to each element, returning a `Result` in an applicative context.",
876			"The option to partition."
877		)]
878		///
879		#[document_returns("The partitioned option wrapped in the applicative context.")]
880		#[document_examples]
881		///
882		/// ```
883		/// use fp_library::{
884		/// 	brands::*,
885		/// 	functions::*,
886		/// };
887		///
888		/// let x = Some(5);
889		/// let y =
890		/// 	wilt::<OptionBrand, OptionBrand, _, _, _>(|a| Some(if a > 2 { Ok(a) } else { Err(a) }), x);
891		/// assert_eq!(y, Some((None, Some(5))));
892		/// ```
893		fn wilt<'a, M: Applicative, A: 'a + Clone, E: 'a + Clone, O: 'a + Clone>(
894			func: impl Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
895			+ 'a,
896			ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
897		) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
898		'a,
899		(
900			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
901			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
902		),
903	>)
904		where
905			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
906			Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone, {
907			match ta {
908				Some(a) => M::map(
909					|res| match res {
910						Ok(o) => (None, Some(o)),
911						Err(e) => (Some(e), None),
912					},
913					func(a),
914				),
915				None => M::pure((None, None)),
916			}
917		}
918
919		/// Maps a function over an option and filters out `None` results in an applicative context.
920		///
921		/// This method maps a function over an option and filters out `None` results in an applicative context.
922		#[document_signature]
923		///
924		#[document_type_parameters(
925			"The lifetime of the values.",
926			"The applicative context.",
927			"The type of the elements in the input structure.",
928			"The type of the result of applying the function."
929		)]
930		///
931		#[document_parameters(
932			"The function to apply to each element, returning an `Option` in an applicative context.",
933			"The option to filter and map."
934		)]
935		///
936		#[document_returns("The filtered and mapped option wrapped in the applicative context.")]
937		#[document_examples]
938		///
939		/// ```
940		/// use fp_library::{
941		/// 	brands::*,
942		/// 	functions::*,
943		/// };
944		///
945		/// let x = Some(5);
946		/// let y = wither::<OptionBrand, OptionBrand, _, _>(
947		/// 	|a| Some(if a > 2 { Some(a * 2) } else { None }),
948		/// 	x,
949		/// );
950		/// assert_eq!(y, Some(Some(10)));
951		/// ```
952		fn wither<'a, M: Applicative, A: 'a + Clone, B: 'a + Clone>(
953			func: impl Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>) + 'a,
954			ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
955		) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
956		'a,
957		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
958	>)
959		where
960			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
961			Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone, {
962			match ta {
963				Some(a) => func(a),
964				None => M::pure(None),
965			}
966		}
967	}
968
969	impl MonadRec for OptionBrand {
970		/// Performs tail-recursive monadic computation over [`Option`].
971		///
972		/// Iteratively applies the step function. If the function returns [`None`],
973		/// the computation short-circuits. If it returns `Some(ControlFlow::Continue(a))`, the
974		/// loop continues with the new state. If it returns `Some(ControlFlow::Break(b))`,
975		/// the computation completes with `Some(b)`.
976		#[document_signature]
977		///
978		#[document_type_parameters(
979			"The lifetime of the computation.",
980			"The type of the initial value and loop state.",
981			"The type of the result."
982		)]
983		///
984		#[document_parameters("The step function.", "The initial value.")]
985		///
986		#[document_returns(
987			"The result of the computation, or `None` if the step function returned `None`."
988		)]
989		///
990		#[document_examples]
991		///
992		/// ```
993		/// use {
994		/// 	core::ops::ControlFlow,
995		/// 	fp_library::{
996		/// 		brands::*,
997		/// 		functions::*,
998		/// 		types::*,
999		/// 	},
1000		/// };
1001		///
1002		/// let result = tail_rec_m::<OptionBrand, _, _>(
1003		/// 	|n| {
1004		/// 		if n < 10 { Some(ControlFlow::Continue(n + 1)) } else { Some(ControlFlow::Break(n)) }
1005		/// 	},
1006		/// 	0,
1007		/// );
1008		/// assert_eq!(result, Some(10));
1009		/// ```
1010		fn tail_rec_m<'a, A: 'a, B: 'a>(
1011			func: impl Fn(
1012				A,
1013			)
1014				-> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, ControlFlow<B, A>>)
1015			+ 'a,
1016			initial: A,
1017		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1018			let mut current = initial;
1019			loop {
1020				match func(current) {
1021					None => return None,
1022					Some(ControlFlow::Continue(next)) => current = next,
1023					Some(ControlFlow::Break(b)) => return Some(b),
1024				}
1025			}
1026		}
1027	}
1028}
1029
1030#[cfg(test)]
1031mod tests {
1032
1033	use {
1034		crate::{
1035			brands::*,
1036			classes::CloneableFn,
1037			functions::*,
1038		},
1039		quickcheck_macros::quickcheck,
1040	};
1041
1042	// Functor Laws
1043
1044	/// Tests the identity law for Functor.
1045	#[quickcheck]
1046	fn functor_identity(x: Option<i32>) -> bool {
1047		map::<OptionBrand, _, _>(identity, x) == x
1048	}
1049
1050	/// Tests the composition law for Functor.
1051	#[quickcheck]
1052	fn functor_composition(x: Option<i32>) -> bool {
1053		let f = |x: i32| x.wrapping_add(1);
1054		let g = |x: i32| x.wrapping_mul(2);
1055		map::<OptionBrand, _, _>(compose(f, g), x)
1056			== map::<OptionBrand, _, _>(f, map::<OptionBrand, _, _>(g, x))
1057	}
1058
1059	// Applicative Laws
1060
1061	/// Tests the identity law for Applicative.
1062	#[quickcheck]
1063	fn applicative_identity(v: Option<i32>) -> bool {
1064		apply::<RcFnBrand, OptionBrand, _, _>(
1065			pure::<OptionBrand, _>(<RcFnBrand as CloneableFn>::new(identity)),
1066			v,
1067		) == v
1068	}
1069
1070	/// Tests the homomorphism law for Applicative.
1071	#[quickcheck]
1072	fn applicative_homomorphism(x: i32) -> bool {
1073		let f = |x: i32| x.wrapping_mul(2);
1074		apply::<RcFnBrand, OptionBrand, _, _>(
1075			pure::<OptionBrand, _>(<RcFnBrand as CloneableFn>::new(f)),
1076			pure::<OptionBrand, _>(x),
1077		) == pure::<OptionBrand, _>(f(x))
1078	}
1079
1080	/// Tests the composition law for Applicative.
1081	#[quickcheck]
1082	fn applicative_composition(
1083		w: Option<i32>,
1084		u_is_some: bool,
1085		v_is_some: bool,
1086	) -> bool {
1087		let v_fn = |x: i32| x.wrapping_mul(2);
1088		let u_fn = |x: i32| x.wrapping_add(1);
1089
1090		let v = if v_is_some {
1091			pure::<OptionBrand, _>(<RcFnBrand as CloneableFn>::new(v_fn))
1092		} else {
1093			None
1094		};
1095		let u = if u_is_some {
1096			pure::<OptionBrand, _>(<RcFnBrand as CloneableFn>::new(u_fn))
1097		} else {
1098			None
1099		};
1100
1101		// RHS: u <*> (v <*> w)
1102		let vw = apply::<RcFnBrand, OptionBrand, _, _>(v.clone(), w);
1103		let rhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), vw);
1104
1105		// LHS: pure(compose) <*> u <*> v <*> w
1106		// equivalent to (u . v) <*> w
1107		let uv = match (u, v) {
1108			(Some(uf), Some(vf)) => {
1109				let composed = move |x| uf(vf(x));
1110				Some(<RcFnBrand as CloneableFn>::new(composed))
1111			}
1112			_ => None,
1113		};
1114
1115		let lhs = apply::<RcFnBrand, OptionBrand, _, _>(uv, w);
1116
1117		lhs == rhs
1118	}
1119
1120	/// Tests the interchange law for Applicative.
1121	#[quickcheck]
1122	fn applicative_interchange(y: i32) -> bool {
1123		// u <*> pure y = pure ($ y) <*> u
1124		let f = |x: i32| x.wrapping_mul(2);
1125		let u = pure::<OptionBrand, _>(<RcFnBrand as CloneableFn>::new(f));
1126
1127		let lhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), pure::<OptionBrand, _>(y));
1128
1129		let rhs_fn =
1130			<RcFnBrand as CloneableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
1131		let rhs = apply::<RcFnBrand, OptionBrand, _, _>(pure::<OptionBrand, _>(rhs_fn), u);
1132
1133		lhs == rhs
1134	}
1135
1136	// Monad Laws
1137
1138	/// Tests the left identity law for Monad.
1139	#[quickcheck]
1140	fn monad_left_identity(a: i32) -> bool {
1141		let f = |x: i32| Some(x.wrapping_mul(2));
1142		bind::<OptionBrand, _, _>(pure::<OptionBrand, _>(a), f) == f(a)
1143	}
1144
1145	/// Tests the right identity law for Monad.
1146	#[quickcheck]
1147	fn monad_right_identity(m: Option<i32>) -> bool {
1148		bind::<OptionBrand, _, _>(m, pure::<OptionBrand, _>) == m
1149	}
1150
1151	/// Tests the associativity law for Monad.
1152	#[quickcheck]
1153	fn monad_associativity(m: Option<i32>) -> bool {
1154		let f = |x: i32| Some(x.wrapping_mul(2));
1155		let g = |x: i32| Some(x.wrapping_add(1));
1156		bind::<OptionBrand, _, _>(bind::<OptionBrand, _, _>(m, f), g)
1157			== bind::<OptionBrand, _, _>(m, |x| bind::<OptionBrand, _, _>(f(x), g))
1158	}
1159
1160	// Edge Cases
1161
1162	/// Tests `map` on `None`.
1163	#[test]
1164	fn map_none() {
1165		assert_eq!(map::<OptionBrand, _, _>(|x: i32| x + 1, None), None);
1166	}
1167
1168	/// Tests `bind` on `None`.
1169	#[test]
1170	fn bind_none() {
1171		assert_eq!(bind::<OptionBrand, _, _>(None, |x: i32| Some(x + 1)), None);
1172	}
1173
1174	/// Tests `bind` returning `None`.
1175	#[test]
1176	fn bind_returning_none() {
1177		assert_eq!(bind::<OptionBrand, _, _>(Some(5), |_| None::<i32>), None);
1178	}
1179
1180	/// Tests `fold_right` on `None`.
1181	#[test]
1182	fn fold_right_none() {
1183		assert_eq!(
1184			crate::classes::foldable::fold_right::<RcFnBrand, OptionBrand, _, _>(
1185				|x: i32, acc| x + acc,
1186				0,
1187				None
1188			),
1189			0
1190		);
1191	}
1192
1193	/// Tests `fold_left` on `None`.
1194	#[test]
1195	fn fold_left_none() {
1196		assert_eq!(
1197			crate::classes::foldable::fold_left::<RcFnBrand, OptionBrand, _, _>(
1198				|acc, x: i32| acc + x,
1199				0,
1200				None
1201			),
1202			0
1203		);
1204	}
1205
1206	/// Tests `traverse` on `None`.
1207	#[test]
1208	fn traverse_none() {
1209		assert_eq!(
1210			crate::classes::traversable::traverse::<OptionBrand, _, _, OptionBrand>(
1211				|x: i32| Some(x + 1),
1212				None
1213			),
1214			Some(None)
1215		);
1216	}
1217
1218	/// Tests `traverse` returning `None`.
1219	#[test]
1220	fn traverse_returning_none() {
1221		assert_eq!(
1222			crate::classes::traversable::traverse::<OptionBrand, _, _, OptionBrand>(
1223				|_: i32| None::<i32>,
1224				Some(5)
1225			),
1226			None
1227		);
1228	}
1229
1230	// MonadRec tests
1231
1232	/// Tests the MonadRec identity law: `tail_rec_m(|a| pure(Done(a)), x) == pure(x)`.
1233	#[quickcheck]
1234	fn monad_rec_identity(x: i32) -> bool {
1235		use {
1236			crate::classes::monad_rec::tail_rec_m,
1237			core::ops::ControlFlow,
1238		};
1239		tail_rec_m::<OptionBrand, _, _>(|a| Some(ControlFlow::Break(a)), x) == Some(x)
1240	}
1241
1242	/// Tests a recursive computation that sums a range via `tail_rec_m`.
1243	#[test]
1244	fn monad_rec_sum_range() {
1245		use {
1246			crate::classes::monad_rec::tail_rec_m,
1247			core::ops::ControlFlow,
1248		};
1249		// Sum 1..=100 using tail_rec_m
1250		let result = tail_rec_m::<OptionBrand, _, _>(
1251			|(n, acc)| {
1252				if n == 0 {
1253					Some(ControlFlow::Break(acc))
1254				} else {
1255					Some(ControlFlow::Continue((n - 1, acc + n)))
1256				}
1257			},
1258			(100i64, 0i64),
1259		);
1260		assert_eq!(result, Some(5050));
1261	}
1262
1263	/// Tests that `tail_rec_m` short-circuits on `None`.
1264	#[test]
1265	fn monad_rec_short_circuit() {
1266		use {
1267			crate::classes::monad_rec::tail_rec_m,
1268			core::ops::ControlFlow,
1269		};
1270		let result: Option<i32> = tail_rec_m::<OptionBrand, _, _>(
1271			|n| {
1272				if n == 5 { None } else { Some(ControlFlow::Continue(n + 1)) }
1273			},
1274			0,
1275		);
1276		assert_eq!(result, None);
1277	}
1278
1279	/// Tests stack safety: `tail_rec_m` handles large iteration counts.
1280	#[test]
1281	fn monad_rec_stack_safety() {
1282		use {
1283			crate::classes::monad_rec::tail_rec_m,
1284			core::ops::ControlFlow,
1285		};
1286		let iterations: i64 = 200_000;
1287		let result = tail_rec_m::<OptionBrand, _, _>(
1288			|acc| {
1289				if acc < iterations {
1290					Some(ControlFlow::Continue(acc + 1))
1291				} else {
1292					Some(ControlFlow::Break(acc))
1293				}
1294			},
1295			0i64,
1296		);
1297		assert_eq!(result, Some(iterations));
1298	}
1299}