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}