1use crate::functor::Functor;
5use crate::hkt::OptionF;
6use crate::hkt::ResultF;
7#[cfg(any(feature = "std", feature = "alloc"))]
8use crate::hkt::VecF;
9#[cfg(all(not(feature = "std"), feature = "alloc"))]
10use alloc::vec::Vec;
11
12pub trait Apply: Functor {
17 fn ap<A, B, F>(ff: Self::Of<F>, fa: Self::Of<A>) -> Self::Of<B>
18 where
19 A: Clone,
20 F: Fn(A) -> B;
21}
22
23impl Apply for OptionF {
24 fn ap<A, B, F>(ff: Option<F>, fa: Option<A>) -> Option<B>
25 where
26 A: Clone,
27 F: Fn(A) -> B,
28 {
29 match (ff, fa) {
30 (Some(f), Some(a)) => Some(f(a)),
31 _ => None,
32 }
33 }
34}
35
36impl<E> Apply for ResultF<E> {
37 fn ap<A, B, F>(ff: Result<F, E>, fa: Result<A, E>) -> Result<B, E>
38 where
39 A: Clone,
40 F: Fn(A) -> B,
41 {
42 match (ff, fa) {
43 (Ok(f), Ok(a)) => Ok(f(a)),
44 (Err(e), _) => Err(e),
45 (_, Err(e)) => Err(e),
46 }
47 }
48}
49
50#[cfg(any(feature = "std", feature = "alloc"))]
51impl Apply for VecF {
52 fn ap<A, B, F>(ff: Vec<F>, fa: Vec<A>) -> Vec<B>
53 where
54 A: Clone,
55 F: Fn(A) -> B,
56 {
57 let mut result = Vec::with_capacity(ff.len() * fa.len());
58 for f in &ff {
59 for a in &fa {
60 result.push(f(a.clone()));
61 }
62 }
63 result
64 }
65}
66
67impl Apply for crate::hkt::IdentityF {
68 fn ap<A, B, F>(ff: F, fa: A) -> B
69 where
70 A: Clone,
71 F: Fn(A) -> B,
72 {
73 ff(fa)
74 }
75}
76
77#[cfg(any(feature = "std", feature = "alloc"))]
78impl Apply for crate::hkt::NonEmptyVecF {
79 fn ap<A, B, F>(
80 ff: crate::hkt::NonEmptyVec<F>,
81 fa: crate::hkt::NonEmptyVec<A>,
82 ) -> crate::hkt::NonEmptyVec<B>
83 where
84 A: Clone,
85 F: Fn(A) -> B,
86 {
87 let head = (ff.head)(fa.head.clone());
89 let mut tail = Vec::new();
90 for a in &fa.tail {
91 tail.push((ff.head)(a.clone()));
92 }
93 for f in &ff.tail {
94 tail.push(f(fa.head.clone()));
95 for a in &fa.tail {
96 tail.push(f(a.clone()));
97 }
98 }
99 crate::hkt::NonEmptyVec::new(head, tail)
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn option_ap_some() {
109 let f: Option<fn(i32) -> i32> = Some(|x| x * 2);
110 assert_eq!(OptionF::ap(f, Some(3)), Some(6));
111 }
112
113 #[test]
114 fn option_ap_none_fn() {
115 let f: Option<fn(i32) -> i32> = None;
116 assert_eq!(OptionF::ap(f, Some(3)), None);
117 }
118
119 #[test]
120 fn option_ap_none_val() {
121 let f: Option<fn(i32) -> i32> = Some(|x| x * 2);
122 assert_eq!(OptionF::ap(f, None), None);
123 }
124
125 #[test]
126 fn result_ap_ok() {
127 let f: Result<fn(i32) -> i32, &str> = Ok(|x| x + 1);
128 assert_eq!(ResultF::<&str>::ap(f, Ok(5)), Ok(6));
129 }
130
131 #[test]
132 fn result_ap_err() {
133 let f: Result<fn(i32) -> i32, &str> = Err("bad");
134 assert_eq!(ResultF::<&str>::ap(f, Ok(5)), Err("bad"));
135 }
136
137 #[test]
138 fn vec_ap() {
139 let fs: Vec<fn(i32) -> i32> = vec![|x| x + 1, |x| x * 10];
140 assert_eq!(VecF::ap(fs, vec![1, 2, 3]), vec![2, 3, 4, 10, 20, 30]);
141 }
142}
143
144#[cfg(test)]
145mod law_tests {
146 use super::*;
147 use proptest::prelude::*;
148
149 proptest! {
152 #[test]
153 fn option_composition(x in any::<i16>()) {
154 let f: Option<fn(i16) -> i16> = Some(|a| a.wrapping_add(1));
155 let g: Option<fn(i16) -> i16> = Some(|a| a.wrapping_mul(2));
156
157 let right = OptionF::ap(f, OptionF::ap(g, Some(x)));
159
160 let composed: Option<fn(i16) -> i16> = Some(|a| a.wrapping_mul(2).wrapping_add(1));
162 let left = OptionF::ap(composed, Some(x));
163
164 prop_assert_eq!(left, right);
165 }
166
167 #[test]
168 fn vec_composition(x in prop::collection::vec(any::<i8>(), 0..5)) {
169 let f: Vec<fn(i8) -> i8> = vec![|a| a.wrapping_add(1)];
170 let g: Vec<fn(i8) -> i8> = vec![|a| a.wrapping_mul(2)];
171
172 let right = VecF::ap(f, VecF::ap(g, x.clone()));
173
174 let composed: Vec<fn(i8) -> i8> = vec![|a| a.wrapping_mul(2).wrapping_add(1)];
175 let left = VecF::ap(composed, x);
176
177 prop_assert_eq!(left, right);
178 }
179 }
180}