fp_library/types/
option.rs

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