fp_library/classes/foldable.rs
1use super::monoid::Monoid;
2use crate::hkt::{Apply1L1T, Kind1L1T};
3
4/// A type class for structures that can be folded to a single value.
5///
6/// A `Foldable` represents a structure that can be folded over to combine its elements
7/// into a single result.
8pub trait Foldable: Kind1L1T {
9 /// Folds the structure by applying a function from right to left.
10 ///
11 /// # Type Signature
12 ///
13 /// `forall a b. Foldable t => ((a, b) -> b, b, t a) -> b`
14 ///
15 /// # Parameters
16 ///
17 /// * `f`: The function to apply to each element and the accumulator.
18 /// * `init`: The initial value of the accumulator.
19 /// * `fa`: The structure to fold.
20 ///
21 /// # Returns
22 ///
23 /// The final accumulator value.
24 ///
25 /// # Examples
26 ///
27 /// ```
28 /// use fp_library::classes::foldable::Foldable;
29 /// use fp_library::brands::OptionBrand;
30 ///
31 /// let x = Some(5);
32 /// let y = OptionBrand::fold_right(|a, b| a + b, 10, x);
33 /// assert_eq!(y, 15);
34 /// ```
35 fn fold_right<'a, A: 'a, B: 'a, F>(
36 f: F,
37 init: B,
38 fa: Apply1L1T<'a, Self, A>,
39 ) -> B
40 where
41 F: Fn(A, B) -> B + 'a;
42
43 /// Folds the structure by applying a function from left to right.
44 ///
45 /// # Type Signature
46 ///
47 /// `forall a b. Foldable t => ((b, a) -> b, b, t a) -> b`
48 ///
49 /// # Parameters
50 ///
51 /// * `f`: The function to apply to the accumulator and each element.
52 /// * `init`: The initial value of the accumulator.
53 /// * `fa`: The structure to fold.
54 ///
55 /// # Returns
56 ///
57 /// The final accumulator value.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use fp_library::classes::foldable::Foldable;
63 /// use fp_library::brands::OptionBrand;
64 ///
65 /// let x = Some(5);
66 /// let y = OptionBrand::fold_left(|b, a| b + a, 10, x);
67 /// assert_eq!(y, 15);
68 /// ```
69 fn fold_left<'a, A: 'a, B: 'a, F>(
70 f: F,
71 init: B,
72 fa: Apply1L1T<'a, Self, A>,
73 ) -> B
74 where
75 F: Fn(B, A) -> B + 'a;
76
77 /// Maps values to a monoid and combines them.
78 ///
79 /// # Type Signature
80 ///
81 /// `forall a m. (Foldable t, Monoid m) => ((a) -> m, t a) -> m`
82 ///
83 /// # Parameters
84 ///
85 /// * `f`: The function to map each element to a monoid.
86 /// * `fa`: The structure to fold.
87 ///
88 /// # Returns
89 ///
90 /// The combined monoid value.
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use fp_library::classes::foldable::Foldable;
96 /// use fp_library::brands::OptionBrand;
97 /// use fp_library::types::string; // Import Monoid impl for String
98 ///
99 /// let x = Some(5);
100 /// let y = OptionBrand::fold_map(|a: i32| a.to_string(), x);
101 /// assert_eq!(y, "5".to_string());
102 /// ```
103 fn fold_map<'a, A: 'a, M, F>(
104 f: F,
105 fa: Apply1L1T<'a, Self, A>,
106 ) -> M
107 where
108 M: Monoid + 'a,
109 F: Fn(A) -> M + 'a;
110}
111
112/// Folds the structure by applying a function from right to left.
113///
114/// Free function version that dispatches to [the type class' associated function][`Foldable::fold_right`].
115///
116/// # Type Signature
117///
118/// `forall a b. Foldable t => ((a, b) -> b, b, t a) -> b`
119///
120/// # Parameters
121///
122/// * `f`: The function to apply to each element and the accumulator.
123/// * `init`: The initial value of the accumulator.
124/// * `fa`: The structure to fold.
125///
126/// # Returns
127///
128/// The final accumulator value.
129///
130/// # Examples
131///
132/// ```
133/// use fp_library::classes::foldable::fold_right;
134/// use fp_library::brands::OptionBrand;
135///
136/// let x = Some(5);
137/// let y = fold_right::<OptionBrand, _, _, _>(|a, b| a + b, 10, x);
138/// assert_eq!(y, 15);
139/// ```
140pub fn fold_right<'a, Brand: Foldable, A: 'a, B: 'a, F>(
141 f: F,
142 init: B,
143 fa: Apply1L1T<'a, Brand, A>,
144) -> B
145where
146 F: Fn(A, B) -> B + 'a,
147{
148 Brand::fold_right(f, init, fa)
149}
150
151/// Folds the structure by applying a function from left to right.
152///
153/// Free function version that dispatches to [the type class' associated function][`Foldable::fold_left`].
154///
155/// # Type Signature
156///
157/// `forall a b. Foldable t => ((b, a) -> b, b, t a) -> b`
158///
159/// # Parameters
160///
161/// * `f`: The function to apply to the accumulator and each element.
162/// * `init`: The initial value of the accumulator.
163/// * `fa`: The structure to fold.
164///
165/// # Returns
166///
167/// The final accumulator value.
168///
169/// # Examples
170///
171/// ```
172/// use fp_library::classes::foldable::fold_left;
173/// use fp_library::brands::OptionBrand;
174///
175/// let x = Some(5);
176/// let y = fold_left::<OptionBrand, _, _, _>(|b, a| b + a, 10, x);
177/// assert_eq!(y, 15);
178/// ```
179pub fn fold_left<'a, Brand: Foldable, A: 'a, B: 'a, F>(
180 f: F,
181 init: B,
182 fa: Apply1L1T<'a, Brand, A>,
183) -> B
184where
185 F: Fn(B, A) -> B + 'a,
186{
187 Brand::fold_left(f, init, fa)
188}
189
190/// Maps values to a monoid and combines them.
191///
192/// Free function version that dispatches to [the type class' associated function][`Foldable::fold_map`].
193///
194/// # Type Signature
195///
196/// `forall a m. (Foldable t, Monoid m) => ((a) -> m, t a) -> m`
197///
198/// # Parameters
199///
200/// * `f`: The function to map each element to a monoid.
201/// * `fa`: The structure to fold.
202///
203/// # Returns
204///
205/// The combined monoid value.
206///
207/// # Examples
208///
209/// ```
210/// use fp_library::classes::foldable::fold_map;
211/// use fp_library::brands::OptionBrand;
212/// use fp_library::types::string; // Import Monoid impl for String
213///
214/// let x = Some(5);
215/// let y = fold_map::<OptionBrand, _, _, _>(|a: i32| a.to_string(), x);
216/// assert_eq!(y, "5".to_string());
217/// ```
218pub fn fold_map<'a, Brand: Foldable, A: 'a, M, F>(
219 f: F,
220 fa: Apply1L1T<'a, Brand, A>,
221) -> M
222where
223 M: Monoid + 'a,
224 F: Fn(A) -> M + 'a,
225{
226 Brand::fold_map(f, fa)
227}