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, foldable::Foldable, functor::Functor, lift::Lift, monoid::Monoid,
11		par_foldable::ParFoldable, pointed::Pointed, semiapplicative::Semiapplicative,
12		semimonad::Semimonad, send_clonable_fn::SendClonableFn, traversable::Traversable,
13	},
14	impl_kind,
15	kinds::*,
16};
17
18impl_kind! {
19	for OptionBrand {
20		type Of<'a, A: 'a>: 'a = Option<A>;
21	}
22}
23
24impl Functor for OptionBrand {
25	/// Maps a function over the value in the option.
26	///
27	/// 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`.
28	///
29	/// ### Type Signature
30	///
31	/// `forall a b. Functor Option => (a -> b, Option a) -> Option b`
32	///
33	/// ### Parameters
34	///
35	/// * `f`: The function to apply to the value.
36	/// * `fa`: The option to map over.
37	///
38	/// ### Returns
39	///
40	/// A new option containing the result of applying the function, or `None`.
41	///
42	/// ### Examples
43	///
44	/// ```
45	/// use fp_library::classes::functor::Functor;
46	/// use fp_library::brands::OptionBrand;
47	///
48	/// let x = Some(5);
49	/// let y = OptionBrand::map(|i| i * 2, x);
50	/// assert_eq!(y, Some(10));
51	///
52	/// // Using the free function
53	/// use fp_library::classes::functor::map;
54	/// assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x * 2, Some(5)), Some(10));
55	/// assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x * 2, None), None);
56	/// ```
57	fn map<'a, F, A: 'a, B: 'a>(
58		f: F,
59		fa: Apply!(
60			brand: Self,
61			signature: ('a, A: 'a) -> 'a,
62		),
63	) -> Apply!(
64		brand: Self,
65		signature: ('a, B: 'a) -> 'a,
66	)
67	where
68		F: Fn(A) -> B + 'a,
69	{
70		fa.map(f)
71	}
72}
73
74impl Lift for OptionBrand {
75	/// Lifts a binary function into the option context.
76	///
77	/// This method lifts a binary function to operate on values within the option context.
78	///
79	/// ### Type Signature
80	///
81	/// `forall a b c. Lift Option => ((a, b) -> c, Option a, Option b) -> Option c`
82	///
83	/// ### Parameters
84	///
85	/// * `f`: The binary function to apply.
86	/// * `fa`: The first option.
87	/// * `fb`: The second option.
88	///
89	/// ### Returns
90	///
91	/// `Some(f(a, b))` if both options are `Some`, otherwise `None`.
92	///
93	/// ### Examples
94	///
95	/// ```
96	/// use fp_library::classes::lift::Lift;
97	/// use fp_library::brands::OptionBrand;
98	///
99	/// let x = Some(1);
100	/// let y = Some(2);
101	/// let z = OptionBrand::lift2(|a, b| a + b, x, y);
102	/// assert_eq!(z, Some(3));
103	///
104	/// // Using the free function
105	/// use fp_library::classes::lift::lift2;
106	/// assert_eq!(lift2::<OptionBrand, _, _, _, _>(|x: i32, y: i32| x + y, Some(1), Some(2)), Some(3));
107	/// assert_eq!(lift2::<OptionBrand, _, _, _, _>(|x: i32, y: i32| x + y, Some(1), None), None);
108	/// ```
109	fn lift2<'a, F, A, B, C>(
110		f: F,
111		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
112		fb: Apply!(brand: Self, signature: ('a, B: 'a) -> 'a),
113	) -> Apply!(brand: Self, signature: ('a, C: 'a) -> 'a)
114	where
115		F: Fn(A, B) -> C + 'a,
116		A: 'a,
117		B: 'a,
118		C: 'a,
119	{
120		fa.zip(fb).map(|(a, b)| f(a, b))
121	}
122}
123
124impl Pointed for OptionBrand {
125	/// Wraps a value in an option.
126	///
127	/// This method wraps a value in an option context.
128	///
129	/// ### Type Signature
130	///
131	/// `forall a. Pointed Option => a -> Option a`
132	///
133	/// ### Parameters
134	///
135	/// * `a`: The value to wrap.
136	///
137	/// ### Returns
138	///
139	/// `Some(a)`.
140	///
141	/// ### Examples
142	///
143	/// ```
144	/// use fp_library::classes::pointed::Pointed;
145	/// use fp_library::brands::OptionBrand;
146	///
147	/// let x = OptionBrand::pure(5);
148	/// assert_eq!(x, Some(5));
149	///
150	/// // Using the free function
151	/// use fp_library::classes::pointed::pure;
152	/// assert_eq!(pure::<OptionBrand, _>(5), Some(5));
153	/// ```
154	fn pure<'a, A: 'a>(a: A) -> Apply!(brand: Self, signature: ('a, A: 'a) -> 'a) {
155		Some(a)
156	}
157}
158
159impl ApplyFirst for OptionBrand {}
160impl ApplySecond for OptionBrand {}
161
162impl Semiapplicative for OptionBrand {
163	/// Applies a wrapped function to a wrapped value.
164	///
165	/// This method applies a function wrapped in an option to a value wrapped in an option.
166	///
167	/// ### Type Signature
168	///
169	/// `forall a b. Semiapplicative Option => (Option (a -> b), Option a) -> Option b`
170	///
171	/// ### Parameters
172	///
173	/// * `ff`: The option containing the function.
174	/// * `fa`: The option containing the value.
175	///
176	/// ### Returns
177	///
178	/// `Some(f(a))` if both are `Some`, otherwise `None`.
179	///
180	/// ### Examples
181	///
182	/// ```
183	/// use fp_library::classes::semiapplicative::Semiapplicative;
184	/// use fp_library::classes::clonable_fn::ClonableFn;
185	/// use fp_library::brands::{OptionBrand};
186	/// use fp_library::brands::RcFnBrand;
187	/// use std::rc::Rc;
188	///
189	/// let f = Some(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
190	/// let x = Some(5);
191	/// let y = OptionBrand::apply::<RcFnBrand, i32, i32>(f, x);
192	/// assert_eq!(y, Some(10));
193	///
194	/// // Using the free function
195	/// use fp_library::classes::semiapplicative::apply;
196	/// let f = Some(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
197	/// assert_eq!(apply::<RcFnBrand, OptionBrand, _, _>(f, Some(5)), Some(10));
198	/// ```
199	fn apply<'a, FnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
200		ff: Apply!(brand: Self, signature: ('a, Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, B)): 'a) -> 'a),
201		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
202	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) {
203		match (ff, fa) {
204			(Some(f), Some(a)) => Some(f(a)),
205			_ => None,
206		}
207	}
208}
209
210impl Semimonad for OptionBrand {
211	/// Chains option computations.
212	///
213	/// This method chains two option computations, where the second computation depends on the result of the first.
214	///
215	/// ### Type Signature
216	///
217	/// `forall a b. Semimonad Option => (Option a, a -> Option b) -> Option b`
218	///
219	/// ### Parameters
220	///
221	/// * `ma`: The first option.
222	/// * `f`: The function to apply to the value inside the option.
223	///
224	/// ### Returns
225	///
226	/// The result of applying `f` to the value if `ma` is `Some`, otherwise `None`.
227	///
228	/// ### Examples
229	///
230	/// ```
231	/// use fp_library::classes::semimonad::Semimonad;
232	/// use fp_library::brands::OptionBrand;
233	///
234	/// let x = Some(5);
235	/// let y = OptionBrand::bind(x, |i| Some(i * 2));
236	/// assert_eq!(y, Some(10));
237	///
238	/// // Using the free function
239	/// use fp_library::classes::semimonad::bind;
240	/// assert_eq!(bind::<OptionBrand, _, _, _>(Some(5), |x| Some(x * 2)), Some(10));
241	/// assert_eq!(bind::<OptionBrand, _, _, _>(None, |x: i32| Some(x * 2)), None);
242	/// ```
243	fn bind<'a, F, A: 'a, B: 'a>(
244		ma: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
245		f: F,
246	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
247	where
248		F: Fn(A) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) + 'a,
249	{
250		ma.and_then(f)
251	}
252}
253
254impl Foldable for OptionBrand {
255	/// Folds the option from the right.
256	///
257	/// 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.
258	///
259	/// ### Type Signature
260	///
261	/// `forall a b. Foldable Option => ((a, b) -> b, b, Option a) -> b`
262	///
263	/// ### Parameters
264	///
265	/// * `func`: The folding function.
266	/// * `initial`: The initial value.
267	/// * `fa`: The option to fold.
268	///
269	/// ### Returns
270	///
271	/// `func(a, initial)` if `fa` is `Some(a)`, otherwise `initial`.
272	///
273	/// ### Examples
274	///
275	/// ```
276	/// use fp_library::classes::foldable::Foldable;
277	/// use fp_library::brands::OptionBrand;
278	/// use fp_library::brands::RcFnBrand;
279	///
280	/// let x = Some(5);
281	/// let y = OptionBrand::fold_right::<RcFnBrand, _, _, _>(|a, b| a + b, 10, x);
282	/// assert_eq!(y, 15);
283	///
284	/// // Using the free function
285	/// use fp_library::classes::foldable::fold_right;
286	/// assert_eq!(fold_right::<RcFnBrand, OptionBrand, _, _, _>(|x: i32, acc| x + acc, 0, Some(5)), 5);
287	/// assert_eq!(fold_right::<RcFnBrand, OptionBrand, _, _, _>(|x: i32, acc| x + acc, 0, None), 0);
288	/// ```
289	fn fold_right<'a, FnBrand, Func, A: 'a, B: 'a>(
290		func: Func,
291		initial: B,
292		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
293	) -> B
294	where
295		Func: Fn(A, B) -> B + 'a,
296		FnBrand: ClonableFn + 'a,
297	{
298		match fa {
299			Some(a) => func(a, initial),
300			None => initial,
301		}
302	}
303
304	/// Folds the option from the left.
305	///
306	/// 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.
307	///
308	/// ### Type Signature
309	///
310	/// `forall a b. Foldable Option => ((b, a) -> b, b, Option a) -> b`
311	///
312	/// ### Parameters
313	///
314	/// * `func`: The function to apply to the accumulator and each element.
315	/// * `initial`: The initial value of the accumulator.
316	/// * `fa`: The option to fold.
317	///
318	/// ### Returns
319	///
320	/// `f(initial, a)` if `fa` is `Some(a)`, otherwise `initial`.
321	///
322	/// ### Examples
323	///
324	/// ```
325	/// use fp_library::classes::foldable::Foldable;
326	/// use fp_library::brands::OptionBrand;
327	/// use fp_library::brands::RcFnBrand;
328	///
329	/// let x = Some(5);
330	/// let y = OptionBrand::fold_left::<RcFnBrand, _, _, _>(|b, a| b + a, 10, x);
331	/// assert_eq!(y, 15);
332	///
333	/// // Using the free function
334	/// use fp_library::classes::foldable::fold_left;
335	/// assert_eq!(fold_left::<RcFnBrand, OptionBrand, _, _, _>(|acc, x: i32| acc + x, 0, Some(5)), 5);
336	/// ```
337	fn fold_left<'a, FnBrand, Func, A: 'a, B: 'a>(
338		func: Func,
339		initial: B,
340		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
341	) -> B
342	where
343		Func: Fn(B, A) -> B + 'a,
344		FnBrand: ClonableFn + 'a,
345	{
346		match fa {
347			Some(a) => func(initial, a),
348			None => initial,
349		}
350	}
351
352	/// Maps the value to a monoid and returns it, or returns empty.
353	///
354	/// This method maps the element of the option to a monoid. If the option is `None`, it returns the monoid's identity element.
355	///
356	/// ### Type Signature
357	///
358	/// `forall a m. (Foldable Option, Monoid m) => ((a) -> m, Option a) -> m`
359	///
360	/// ### Parameters
361	///
362	/// * `func`: The mapping function.
363	/// * `fa`: The option to fold.
364	///
365	/// ### Returns
366	///
367	/// `func(a)` if `fa` is `Some(a)`, otherwise `M::empty()`.
368	///
369	/// ### Examples
370	///
371	/// ```
372	/// use fp_library::classes::foldable::Foldable;
373	/// use fp_library::brands::OptionBrand;
374	/// use fp_library::types::string; // Import to bring Monoid impl for String into scope
375	/// use fp_library::brands::RcFnBrand;
376	///
377	/// let x = Some(5);
378	/// let y = OptionBrand::fold_map::<RcFnBrand, _, _, _>(|a: i32| a.to_string(), x);
379	/// assert_eq!(y, "5".to_string());
380	///
381	/// // Using the free function
382	/// use fp_library::classes::foldable::fold_map;
383	/// assert_eq!(fold_map::<RcFnBrand, OptionBrand, _, _, _>(|x: i32| x.to_string(), Some(5)), "5".to_string());
384	/// ```
385	fn fold_map<'a, FnBrand, Func, A: 'a, M>(
386		func: Func,
387		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
388	) -> M
389	where
390		M: Monoid + 'a,
391		Func: Fn(A) -> M + 'a,
392		FnBrand: ClonableFn + 'a,
393	{
394		match fa {
395			Some(a) => func(a),
396			None => M::empty(),
397		}
398	}
399}
400
401impl Traversable for OptionBrand {
402	/// Traverses the option with an applicative function.
403	///
404	/// 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)`.
405	///
406	/// ### Type Signature
407	///
408	/// `forall a b f. (Traversable Option, Applicative f) => (a -> f b, Option a) -> f (Option b)`
409	///
410	/// ### Parameters
411	///
412	/// * `func`: The function to apply to each element, returning a value in an applicative context.
413	/// * `ta`: The option to traverse.
414	///
415	/// ### Returns
416	///
417	/// The option wrapped in the applicative context.
418	///
419	/// ### Examples
420	///
421	/// ```
422	/// use fp_library::classes::traversable::Traversable;
423	/// use fp_library::brands::OptionBrand;
424	///
425	/// let x = Some(5);
426	/// let y = OptionBrand::traverse::<OptionBrand, _, _, _>(|a| Some(a * 2), x);
427	/// assert_eq!(y, Some(Some(10)));
428	///
429	/// // Using the free function
430	/// use fp_library::classes::traversable::traverse;
431	/// assert_eq!(traverse::<OptionBrand, OptionBrand, _, _, _>(|x| Some(x * 2), Some(5)), Some(Some(10)));
432	/// ```
433	fn traverse<'a, F: Applicative, Func, A: 'a + Clone, B: 'a + Clone>(
434		func: Func,
435		ta: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
436	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): 'a) -> 'a)
437	where
438		Func: Fn(A) -> Apply!(brand: F, signature: ('a, B: 'a) -> 'a) + 'a,
439		Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): Clone,
440	{
441		match ta {
442			Some(a) => F::map(|b| Some(b), func(a)),
443			None => F::pure(None),
444		}
445	}
446	/// Sequences an option of applicative.
447	///
448	/// This method evaluates the computation inside the option and wraps the result in the applicative context. If `None`, it returns `pure(None)`.
449	///
450	/// ### Type Signature
451	///
452	/// `forall a f. (Traversable Option, Applicative f) => (Option (f a)) -> f (Option a)`
453	///
454	/// ### Parameters
455	///
456	/// * `ta`: The option containing the applicative value.
457	///
458	/// # Returns
459	///
460	/// The option wrapped in the applicative context.
461	///
462	/// ### Examples
463	///
464	/// ```
465	/// use fp_library::classes::traversable::Traversable;
466	/// use fp_library::brands::OptionBrand;
467	///
468	/// let x = Some(Some(5));
469	/// let y = OptionBrand::sequence::<OptionBrand, _>(x);
470	/// assert_eq!(y, Some(Some(5)));
471	///
472	/// // Using the free function
473	/// use fp_library::classes::traversable::sequence;
474	/// assert_eq!(sequence::<OptionBrand, OptionBrand, _>(Some(Some(5))), Some(Some(5)));
475	/// ```
476	fn sequence<'a, F: Applicative, A: 'a + Clone>(
477		ta: Apply!(brand: Self, signature: ('a, Apply!(brand: F, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
478	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
479	where
480		Apply!(brand: F, signature: ('a, A: 'a) -> 'a): Clone,
481		Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): Clone,
482	{
483		match ta {
484			Some(fa) => F::map(|a| Some(a), fa),
485			None => F::pure(None),
486		}
487	}
488}
489
490impl<FnBrand: SendClonableFn> ParFoldable<FnBrand> for OptionBrand {
491	/// Maps the value to a monoid and returns it, or returns empty, in parallel.
492	///
493	/// 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.
494	///
495	/// ### Type Signature
496	///
497	/// `forall a m. (ParFoldable Option, Monoid m, Send m, Sync m) => (f a m, Option a) -> m`
498	///
499	/// ### Parameters
500	///
501	/// * `func`: The mapping function.
502	/// * `fa`: The option to fold.
503	///
504	/// ### Returns
505	///
506	/// The combined monoid value.
507	///
508	/// ### Examples
509	///
510	/// ```
511	/// use fp_library::classes::par_foldable::ParFoldable;
512	/// use fp_library::brands::{OptionBrand, ArcFnBrand};
513	/// use fp_library::classes::send_clonable_fn::SendClonableFn;
514	/// use fp_library::classes::send_clonable_fn::new_send;
515	///
516	/// let x = Some(1);
517	/// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
518	/// let y = <OptionBrand as ParFoldable<ArcFnBrand>>::par_fold_map(f, x);
519	/// assert_eq!(y, "1".to_string());
520	///
521	/// // Using the free function
522	/// use fp_library::classes::par_foldable::par_fold_map;
523	/// let x = Some(1);
524	/// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
525	/// assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "1".to_string());
526	/// ```
527	fn par_fold_map<'a, A, M>(
528		func: Apply!(brand: FnBrand, kind: SendClonableFn, output: SendOf, lifetimes: ('a), types: (A, M)),
529		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
530	) -> M
531	where
532		A: 'a + Clone + Send + Sync,
533		M: Monoid + Send + Sync + 'a,
534	{
535		match fa {
536			Some(a) => func(a),
537			None => M::empty(),
538		}
539	}
540}
541
542#[cfg(test)]
543mod tests {
544	use super::*;
545	use crate::{
546		brands::{ArcFnBrand, RcFnBrand},
547		classes::{
548			functor::map,
549			par_foldable::{par_fold_map, par_fold_right},
550			pointed::pure,
551			semiapplicative::apply,
552			semimonad::bind,
553			send_clonable_fn::new_send,
554		},
555		functions::{compose, identity},
556	};
557	use quickcheck_macros::quickcheck;
558
559	// Functor Laws
560
561	/// Tests the identity law for Functor.
562	#[quickcheck]
563	fn functor_identity(x: Option<i32>) -> bool {
564		map::<OptionBrand, _, _, _>(identity, x) == x
565	}
566
567	/// Tests the composition law for Functor.
568	#[quickcheck]
569	fn functor_composition(x: Option<i32>) -> bool {
570		let f = |x: i32| x.wrapping_add(1);
571		let g = |x: i32| x.wrapping_mul(2);
572		map::<OptionBrand, _, _, _>(compose(f, g), x)
573			== map::<OptionBrand, _, _, _>(f, map::<OptionBrand, _, _, _>(g, x))
574	}
575
576	// Applicative Laws
577
578	/// Tests the identity law for Applicative.
579	#[quickcheck]
580	fn applicative_identity(v: Option<i32>) -> bool {
581		apply::<RcFnBrand, OptionBrand, _, _>(
582			pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
583			v,
584		) == v
585	}
586
587	/// Tests the homomorphism law for Applicative.
588	#[quickcheck]
589	fn applicative_homomorphism(x: i32) -> bool {
590		let f = |x: i32| x.wrapping_mul(2);
591		apply::<RcFnBrand, OptionBrand, _, _>(
592			pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
593			pure::<OptionBrand, _>(x),
594		) == pure::<OptionBrand, _>(f(x))
595	}
596
597	/// Tests the composition law for Applicative.
598	#[quickcheck]
599	fn applicative_composition(
600		w: Option<i32>,
601		u_is_some: bool,
602		v_is_some: bool,
603	) -> bool {
604		let v_fn = |x: i32| x.wrapping_mul(2);
605		let u_fn = |x: i32| x.wrapping_add(1);
606
607		let v = if v_is_some {
608			pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn))
609		} else {
610			None
611		};
612		let u = if u_is_some {
613			pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn))
614		} else {
615			None
616		};
617
618		// RHS: u <*> (v <*> w)
619		let vw = apply::<RcFnBrand, OptionBrand, _, _>(v.clone(), w.clone());
620		let rhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), vw);
621
622		// LHS: pure(compose) <*> u <*> v <*> w
623		// equivalent to (u . v) <*> w
624		let uv = match (u, v) {
625			(Some(uf), Some(vf)) => {
626				let composed = move |x| uf(vf(x));
627				Some(<RcFnBrand as ClonableFn>::new(composed))
628			}
629			_ => None,
630		};
631
632		let lhs = apply::<RcFnBrand, OptionBrand, _, _>(uv, w);
633
634		lhs == rhs
635	}
636
637	/// Tests the interchange law for Applicative.
638	#[quickcheck]
639	fn applicative_interchange(y: i32) -> bool {
640		// u <*> pure y = pure ($ y) <*> u
641		let f = |x: i32| x.wrapping_mul(2);
642		let u = pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f));
643
644		let lhs = apply::<RcFnBrand, OptionBrand, _, _>(u.clone(), pure::<OptionBrand, _>(y));
645
646		let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
647		let rhs = apply::<RcFnBrand, OptionBrand, _, _>(pure::<OptionBrand, _>(rhs_fn), u);
648
649		lhs == rhs
650	}
651
652	// Monad Laws
653
654	/// Tests the left identity law for Monad.
655	#[quickcheck]
656	fn monad_left_identity(a: i32) -> bool {
657		let f = |x: i32| Some(x.wrapping_mul(2));
658		bind::<OptionBrand, _, _, _>(pure::<OptionBrand, _>(a), f) == f(a)
659	}
660
661	/// Tests the right identity law for Monad.
662	#[quickcheck]
663	fn monad_right_identity(m: Option<i32>) -> bool {
664		bind::<OptionBrand, _, _, _>(m, pure::<OptionBrand, _>) == m
665	}
666
667	/// Tests the associativity law for Monad.
668	#[quickcheck]
669	fn monad_associativity(m: Option<i32>) -> bool {
670		let f = |x: i32| Some(x.wrapping_mul(2));
671		let g = |x: i32| Some(x.wrapping_add(1));
672		bind::<OptionBrand, _, _, _>(bind::<OptionBrand, _, _, _>(m, f), g)
673			== bind::<OptionBrand, _, _, _>(m, |x| bind::<OptionBrand, _, _, _>(f(x), g))
674	}
675
676	// Edge Cases
677
678	/// Tests `map` on `None`.
679	#[test]
680	fn map_none() {
681		assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x + 1, None), None);
682	}
683
684	/// Tests `bind` on `None`.
685	#[test]
686	fn bind_none() {
687		assert_eq!(bind::<OptionBrand, _, _, _>(None, |x: i32| Some(x + 1)), None);
688	}
689
690	/// Tests `bind` returning `None`.
691	#[test]
692	fn bind_returning_none() {
693		assert_eq!(bind::<OptionBrand, _, _, _>(Some(5), |_| None::<i32>), None);
694	}
695
696	/// Tests `fold_right` on `None`.
697	#[test]
698	fn fold_right_none() {
699		assert_eq!(
700			crate::classes::foldable::fold_right::<RcFnBrand, OptionBrand, _, _, _>(
701				|x: i32, acc| x + acc,
702				0,
703				None
704			),
705			0
706		);
707	}
708
709	/// Tests `fold_left` on `None`.
710	#[test]
711	fn fold_left_none() {
712		assert_eq!(
713			crate::classes::foldable::fold_left::<RcFnBrand, OptionBrand, _, _, _>(
714				|acc, x: i32| acc + x,
715				0,
716				None
717			),
718			0
719		);
720	}
721
722	/// Tests `traverse` on `None`.
723	#[test]
724	fn traverse_none() {
725		assert_eq!(
726			crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
727				|x: i32| Some(x + 1),
728				None
729			),
730			Some(None)
731		);
732	}
733
734	/// Tests `traverse` returning `None`.
735	#[test]
736	fn traverse_returning_none() {
737		assert_eq!(
738			crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
739				|_: i32| None::<i32>,
740				Some(5)
741			),
742			None
743		);
744	}
745
746	// ParFoldable Tests
747
748	/// Tests `par_fold_map` on `None`.
749	#[test]
750	fn par_fold_map_none() {
751		let x: Option<i32> = None;
752		let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
753		assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "".to_string());
754	}
755
756	/// Tests `par_fold_map` on `Some`.
757	#[test]
758	fn par_fold_map_some() {
759		let x = Some(5);
760		let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
761		assert_eq!(par_fold_map::<ArcFnBrand, OptionBrand, _, _>(f, x), "5".to_string());
762	}
763
764	/// Tests `par_fold_right` on `Some`.
765	#[test]
766	fn par_fold_right_some() {
767		let x = Some(5);
768		let f = new_send::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
769		assert_eq!(par_fold_right::<ArcFnBrand, OptionBrand, _, _>(f, 10, x), 15);
770	}
771}