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