1#[macro_export]
12macro_rules! pipe {
13 ( $last:expr ) => { $last };
14 ( $head:expr, $($tail:expr), +) => {
15 compose_two($head, pipe!($($tail),+))
16 };
17}
18
19#[macro_export]
25macro_rules! compose {
26 ( $last:expr ) => { $last };
27 ( $head:expr, $($tail:expr), +) => {
28 compose_two(compose!($($tail),+), $head)
29 };
30}
31
32#[macro_export]
36macro_rules! spread_and_call {
37 ($func:expr, $($x:expr), *) => {
38 $func($($x), *);
39 };
40}
41
42#[macro_export]
47macro_rules! partial_left_last_one {
48 ($func:expr, $($x:expr), *) => {
49 |v| spread_and_call!($func, $($x), *, v)
50 };
51}
52
53#[macro_export]
57macro_rules! map {
58 ($func:expr) => {
59 partial_left_last_one!(map, $func)
60 };
61}
62
63#[macro_export]
67macro_rules! filter {
68 ($func:expr) => {
69 partial_left_last_one!(filter, $func)
70 };
71}
72
73#[macro_export]
77macro_rules! reduce {
78 ($func:expr) => {
79 partial_left_last_one!(reduce, $func)
80 };
81}
82
83#[macro_export]
87macro_rules! foldl {
88 ($func:expr, $second:expr) => {
89 partial_left_last_one!(foldl, $func, $second)
90 };
91}
92
93#[macro_export]
97macro_rules! foldr {
98 ($func:expr, $second:expr) => {
99 partial_left_last_one!(foldr, $func, $second)
100 };
101}
102
103#[macro_export]
107macro_rules! reverse {
108 () => {
109 |v| reverse(v)
110 };
111}
112
113#[macro_export]
117macro_rules! contains {
118 ($x:expr) => {
119 partial_left_last_one!(contains, $x)
120 };
121}
122
123#[inline]
135pub fn compose_two<A, B, C, G, F>(f: F, g: G) -> impl FnOnce(A) -> C
136where
137 F: FnOnce(A) -> B,
138 G: FnOnce(B) -> C,
139{
140 move |x| g(f(x))
141}
142
143#[inline]
144pub fn map<T, B>(f: impl FnMut(T) -> B, v: Vec<T>) -> Vec<B> {
145 v.into_iter().map(f).collect::<Vec<B>>()
146}
147
148#[inline]
149pub fn filter<'r, T: 'r>(f: impl FnMut(&T) -> bool, v: Vec<T>) -> Vec<T> {
150 v.into_iter().filter(f).into_iter().collect::<Vec<T>>()
151}
152
153#[inline]
154pub fn foldl<T, B>(f: impl FnMut(B, T) -> B, initial: B, v: Vec<T>) -> B {
155 v.into_iter().fold(initial, f)
156}
157
158#[inline]
159pub fn foldr<T, B>(f: impl FnMut(B, T) -> B, initial: B, v: Vec<T>) -> B {
160 v.into_iter().rev().fold(initial, f)
161}
162
163#[inline]
164pub fn reverse<T>(v: Vec<T>) -> Vec<T> {
165 v.into_iter().rev().collect::<Vec<T>>()
166}
167
168#[inline]
169pub fn contains<T: PartialEq>(x: &T, v: Vec<T>) -> bool {
170 v.contains(x)
171}
172
173pub trait Reduce<T> {
183 fn reduce<F>(self, f: F) -> Option<T>
184 where
185 Self: Sized,
186 F: FnMut(T, T) -> T;
187}
188
189impl<T, I> Reduce<T> for I
190where
191 I: Iterator<Item = T>,
192{
193 #[inline]
194 fn reduce<F>(mut self, f: F) -> Option<T>
195 where
196 Self: Sized,
197 F: FnMut(T, T) -> T,
198 {
199 self.next().map(|first| self.fold(first, f))
200 }
201}
202
203#[inline]
204pub fn reduce<'r, T: 'r>(f: impl FnMut(T, T) -> T, v: Vec<T>) -> Option<T> {
205 Reduce::reduce(v.into_iter(), f)
206}
207
208#[test]
209fn test_compose() {
210 let add = |x| x + 2;
211 let multiply = |x| x * 3;
212 let divide = |x| x / 2;
213
214 let result = (compose!(add, multiply, divide))(10);
215 assert_eq!(17, result);
216 println!("Composed FnOnce Result is {}", result);
217
218 let result = (pipe!(add, multiply, divide))(10);
219 assert_eq!(18, result);
220 println!("Piped FnOnce Result is {}", result);
221}
222
223#[test]
224fn test_map_reduce_filter() {
225 let result =
226 (compose!(reduce!(|a, b| a * b), filter!(|x| *x < 6), map!(|x| x * 2)))(vec![1, 2, 3, 4]);
227 assert_eq!(Some(8), result);
228 println!("test_map_reduce_filter Result is {:?}", result);
229}
230
231#[test]
232fn test_foldl_foldr() {
233 let result = (compose!(
235 foldl!(
236 |a, b| {
237 if a < 4 {
238 return a + b;
239 }
240 return a;
241 },
242 0
243 ),
244 filter!(|x| *x < 6),
245 map!(|x| x * 2)
246 ))(vec![1, 2, 3, 4]);
247 assert_eq!(6, result);
248 println!("foldl Result is {:?}", result);
249
250 let result = (compose!(
252 foldr!(
253 |a, b| {
254 if a < 4 {
255 return a + b;
256 }
257 return a;
258 },
259 0
260 ),
261 filter!(|x| *x < 6),
262 map!(|x| x * 2)
263 ))(vec![1, 2, 3, 4]);
264 assert_eq!(4, result);
265 println!("foldr Result is {:?}", result);
266}
267
268#[test]
269fn test_contains() {
270 assert_eq!(true, contains!(&4)(vec![1, 2, 3, 4]));
271}
272
273#[test]
274fn test_reverse() {
275 assert_eq!(vec![4, 3, 2, 1], reverse!()(vec![1, 2, 3, 4]));
276}