1use crate::functor::Functor;
2use crate::hkt::OptionF;
3use crate::hkt::ResultF;
4#[cfg(any(feature = "std", feature = "alloc"))]
5use crate::hkt::VecF;
6
7pub trait Alt: Functor {
13 fn alt<A>(fa1: Self::Of<A>, fa2: Self::Of<A>) -> Self::Of<A>;
14}
15
16impl Alt for OptionF {
17 fn alt<A>(fa1: Option<A>, fa2: Option<A>) -> Option<A> {
18 fa1.or(fa2)
19 }
20}
21
22impl<E> Alt for ResultF<E> {
23 fn alt<A>(fa1: Result<A, E>, fa2: Result<A, E>) -> Result<A, E> {
24 fa1.or(fa2)
25 }
26}
27
28#[cfg(any(feature = "std", feature = "alloc"))]
29impl Alt for VecF {
30 fn alt<A>(mut fa1: Vec<A>, fa2: Vec<A>) -> Vec<A> {
31 fa1.extend(fa2);
32 fa1
33 }
34}
35
36#[cfg(any(feature = "std", feature = "alloc"))]
37impl Alt for crate::hkt::NonEmptyVecF {
38 fn alt<A>(
39 mut fa1: crate::hkt::NonEmptyVec<A>,
40 fa2: crate::hkt::NonEmptyVec<A>,
41 ) -> crate::hkt::NonEmptyVec<A> {
42 fa1.tail.push(fa2.head);
43 fa1.tail.extend(fa2.tail);
44 fa1
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn option_alt_some_some() {
54 assert_eq!(OptionF::alt(Some(1), Some(2)), Some(1));
55 }
56
57 #[test]
58 fn option_alt_none_some() {
59 assert_eq!(OptionF::alt(None, Some(2)), Some(2));
60 }
61
62 #[test]
63 fn option_alt_none_none() {
64 assert_eq!(OptionF::alt(None::<i32>, None), None);
65 }
66
67 #[test]
68 fn result_alt() {
69 assert_eq!(ResultF::<&str>::alt(Err("a"), Ok(2)), Ok(2));
70 assert_eq!(ResultF::<&str>::alt(Ok(1), Ok(2)), Ok(1));
71 }
72
73 #[test]
74 fn vec_alt() {
75 assert_eq!(VecF::alt(vec![1, 2], vec![3, 4]), vec![1, 2, 3, 4]);
76 }
77}
78
79#[cfg(test)]
80mod law_tests {
81 use super::*;
82 use crate::functor::Functor;
83 use proptest::prelude::*;
84
85 proptest! {
86 #[test]
88 fn option_associativity(
89 a in any::<Option<i32>>(),
90 b in any::<Option<i32>>(),
91 c in any::<Option<i32>>()
92 ) {
93 let left = OptionF::alt(OptionF::alt(a, b), c);
94 let right = OptionF::alt(a, OptionF::alt(b, c));
95 prop_assert_eq!(left, right);
96 }
97
98 #[test]
100 fn option_distributivity(
101 a in any::<Option<i32>>(),
102 b in any::<Option<i32>>()
103 ) {
104 let f = |x: i32| x.wrapping_add(1);
105 let left = OptionF::fmap(OptionF::alt(a, b), f);
106 let right = OptionF::alt(OptionF::fmap(a, f), OptionF::fmap(b, f));
107 prop_assert_eq!(left, right);
108 }
109
110 #[test]
111 fn vec_associativity(
112 a in prop::collection::vec(any::<i32>(), 0..5),
113 b in prop::collection::vec(any::<i32>(), 0..5),
114 c in prop::collection::vec(any::<i32>(), 0..5)
115 ) {
116 let left = VecF::alt(VecF::alt(a.clone(), b.clone()), c.clone());
117 let right = VecF::alt(a, VecF::alt(b, c));
118 prop_assert_eq!(left, right);
119 }
120 }
121}