1use super::monoid::Monoid;
14use crate::{
15 Apply,
16 classes::{cloneable_fn::CloneableFn, semigroup::Semigroup},
17 kinds::*,
18 types::Endofunction,
19};
20use fp_macros::doc_params;
21use fp_macros::doc_type_params;
22use fp_macros::hm_signature;
23
24pub trait Foldable: Kind_cdc7cd43dac7585f {
38 #[hm_signature(Foldable)]
45 #[doc_type_params(
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 #[doc_params(
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 #[hm_signature(Foldable)]
106 #[doc_type_params(
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 #[doc_params(
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 #[hm_signature(Foldable)]
175 #[doc_type_params(
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 #[doc_params("The function to map each element to a monoid.", "The structure to fold.")]
189 fn fold_map<'a, FnBrand, A: 'a + Clone, M, Func>(
204 func: Func,
205 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
206 ) -> M
207 where
208 M: Monoid + 'a,
209 Func: Fn(A) -> M + 'a,
210 FnBrand: CloneableFn + 'a,
211 {
212 Self::fold_right::<FnBrand, A, M, _>(move |a, m| M::append(func(a), m), M::empty(), fa)
213 }
214}
215
216#[hm_signature(Foldable)]
223#[doc_type_params(
227 "The lifetime of the elements.",
228 "The brand of the cloneable function to use.",
229 "The brand of the foldable structure.",
230 "The type of the elements in the structure.",
231 "The type of the accumulator.",
232 "The type of the folding function."
233)]
234#[doc_params(
238 "The function to apply to each element and the accumulator.",
239 "The initial value of the accumulator.",
240 "The structure to fold."
241)]
242pub fn fold_right<'a, FnBrand, Brand: Foldable, A: 'a + Clone, B: 'a, Func>(
257 func: Func,
258 initial: B,
259 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
260) -> B
261where
262 Func: Fn(A, B) -> B + 'a,
263 FnBrand: CloneableFn + 'a,
264{
265 Brand::fold_right::<FnBrand, A, B, Func>(func, initial, fa)
266}
267
268#[hm_signature(Foldable)]
275#[doc_type_params(
279 "The lifetime of the elements.",
280 "The brand of the cloneable function to use.",
281 "The brand of the foldable structure.",
282 "The type of the elements in the structure.",
283 "The type of the accumulator.",
284 "The type of the folding function."
285)]
286#[doc_params(
290 "The function to apply to the accumulator and each element.",
291 "The initial value of the accumulator.",
292 "The structure to fold."
293)]
294pub fn fold_left<'a, FnBrand, Brand: Foldable, A: 'a + Clone, B: 'a, Func>(
309 func: Func,
310 initial: B,
311 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
312) -> B
313where
314 Func: Fn(B, A) -> B + 'a,
315 FnBrand: CloneableFn + 'a,
316{
317 Brand::fold_left::<FnBrand, A, B, Func>(func, initial, fa)
318}
319
320#[hm_signature(Foldable)]
327#[doc_type_params(
331 "The lifetime of the elements.",
332 "The brand of the cloneable function to use.",
333 "The brand of the foldable structure.",
334 "The type of the elements in the structure.",
335 "The type of the monoid.",
336 "The type of the mapping function."
337)]
338#[doc_params("The function to map each element to a monoid.", "The structure to fold.")]
342pub fn fold_map<'a, FnBrand, Brand: Foldable, A: 'a + Clone, M, Func>(
357 func: Func,
358 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
359) -> M
360where
361 M: Monoid + 'a,
362 Func: Fn(A) -> M + 'a,
363 FnBrand: CloneableFn + 'a,
364{
365 Brand::fold_map::<FnBrand, A, M, Func>(func, fa)
366}