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