1use super::monoid::Monoid;
14use crate::{
15 Apply,
16 classes::{cloneable_fn::CloneableFn, semigroup::Semigroup},
17 kinds::*,
18 types::Endofunction,
19};
20use fp_macros::document_parameters;
21use fp_macros::document_signature;
22use fp_macros::document_type_parameters;
23
24pub trait Foldable: Kind_cdc7cd43dac7585f {
38 #[document_signature]
45 #[document_type_parameters(
49 "The lifetime of the elements.",
50 "The brand of the cloneable function to use.",
51 "The type of the elements in the structure.",
52 "The type of the accumulator.",
53 "The type of the folding function."
54 )]
55 #[document_parameters(
59 "The function to apply to each element and the accumulator.",
60 "The initial value of the accumulator.",
61 "The structure to fold."
62 )]
63 fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a, Func>(
78 func: Func,
79 initial: B,
80 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
81 ) -> B
82 where
83 Func: Fn(A, B) -> B + 'a,
84 FnBrand: CloneableFn + 'a,
85 {
86 let f = <FnBrand as CloneableFn>::new(move |(a, b)| func(a, b));
87 let m = Self::fold_map::<FnBrand, A, Endofunction<FnBrand, B>, _>(
88 move |a: A| {
89 let f = f.clone();
90 Endofunction::<FnBrand, B>::new(<FnBrand as CloneableFn>::new(move |b| {
91 f((a.clone(), b))
92 }))
93 },
94 fa,
95 );
96 m.0(initial)
97 }
98
99 #[document_signature]
106 #[document_type_parameters(
110 "The lifetime of the elements.",
111 "The brand of the cloneable function to use.",
112 "The type of the elements in the structure.",
113 "The type of the accumulator.",
114 "The type of the folding function."
115 )]
116 #[document_parameters(
120 "The function to apply to the accumulator and each element.",
121 "The initial value of the accumulator.",
122 "The structure to fold."
123 )]
124 fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a, Func>(
139 func: Func,
140 initial: B,
141 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
142 ) -> B
143 where
144 Func: Fn(B, A) -> B + 'a,
145 FnBrand: CloneableFn + 'a,
146 {
147 let f = <FnBrand as CloneableFn>::new(move |(b, a)| func(b, a));
148 let m = Self::fold_right::<FnBrand, A, Endofunction<FnBrand, B>, _>(
149 move |a: A, k: Endofunction<'a, FnBrand, B>| {
150 let f = f.clone();
151 let current =
157 Endofunction::<FnBrand, B>::new(<FnBrand as CloneableFn>::new(move |b| {
158 f((b, a.clone()))
159 }));
160 Semigroup::append(k, current)
161 },
162 Endofunction::<FnBrand, B>::empty(),
163 fa,
164 );
165 m.0(initial)
166 }
167
168 #[document_signature]
175 #[document_type_parameters(
179 "The lifetime of the elements.",
180 "The brand of the cloneable function to use.",
181 "The type of the elements in the structure.",
182 "The type of the monoid.",
183 "The type of the mapping function."
184 )]
185 #[document_parameters(
189 "The function to map each element to a monoid.",
190 "The structure to fold."
191 )]
192 fn fold_map<'a, FnBrand, A: 'a + Clone, M, Func>(
207 func: Func,
208 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
209 ) -> M
210 where
211 M: Monoid + 'a,
212 Func: Fn(A) -> M + 'a,
213 FnBrand: CloneableFn + 'a,
214 {
215 Self::fold_right::<FnBrand, A, M, _>(move |a, m| M::append(func(a), m), M::empty(), fa)
216 }
217}
218
219#[document_signature]
226#[document_type_parameters(
230 "The lifetime of the elements.",
231 "The brand of the cloneable function to use.",
232 "The brand of the foldable structure.",
233 "The type of the elements in the structure.",
234 "The type of the accumulator.",
235 "The type of the folding function."
236)]
237#[document_parameters(
241 "The function to apply to each element and the accumulator.",
242 "The initial value of the accumulator.",
243 "The structure to fold."
244)]
245pub fn fold_right<'a, FnBrand, Brand: Foldable, A: 'a + Clone, B: 'a, Func>(
260 func: Func,
261 initial: B,
262 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
263) -> B
264where
265 Func: Fn(A, B) -> B + 'a,
266 FnBrand: CloneableFn + 'a,
267{
268 Brand::fold_right::<FnBrand, A, B, Func>(func, initial, fa)
269}
270
271#[document_signature]
278#[document_type_parameters(
282 "The lifetime of the elements.",
283 "The brand of the cloneable function to use.",
284 "The brand of the foldable structure.",
285 "The type of the elements in the structure.",
286 "The type of the accumulator.",
287 "The type of the folding function."
288)]
289#[document_parameters(
293 "The function to apply to the accumulator and each element.",
294 "The initial value of the accumulator.",
295 "The structure to fold."
296)]
297pub fn fold_left<'a, FnBrand, Brand: Foldable, A: 'a + Clone, B: 'a, Func>(
312 func: Func,
313 initial: B,
314 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
315) -> B
316where
317 Func: Fn(B, A) -> B + 'a,
318 FnBrand: CloneableFn + 'a,
319{
320 Brand::fold_left::<FnBrand, A, B, Func>(func, initial, fa)
321}
322
323#[document_signature]
330#[document_type_parameters(
334 "The lifetime of the elements.",
335 "The brand of the cloneable function to use.",
336 "The brand of the foldable structure.",
337 "The type of the elements in the structure.",
338 "The type of the monoid.",
339 "The type of the mapping function."
340)]
341#[document_parameters("The function to map each element to a monoid.", "The structure to fold.")]
345pub fn fold_map<'a, FnBrand, Brand: Foldable, A: 'a + Clone, M, Func>(
360 func: Func,
361 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
362) -> M
363where
364 M: Monoid + 'a,
365 Func: Fn(A) -> M + 'a,
366 FnBrand: CloneableFn + 'a,
367{
368 Brand::fold_map::<FnBrand, A, M, Func>(func, fa)
369}