fp_library/classes/traversable.rs
1use crate::{
2 classes::{Applicative, ClonableFn, Foldable, Functor, clonable_fn::ApplyFn},
3 functions::{identity, map},
4 hkt::Apply0L1T,
5};
6
7/// A type class for traversable functors.
8///
9/// `Traversable` functors can be traversed, which accumulates results and effects in some [`Applicative`] context.
10///
11/// A minimum implementation of `Traversable` requires the manual implementation of at least [`Traversable::traverse`] or [`Traversable::sequence`].
12pub trait Traversable: Functor + Foldable {
13 /// Map each element of the [`Traversable`] structure to a computation, evaluate those computations and combine the results into an [`Applicative`] context.
14 ///
15 /// The default implementation of `traverse` is implemented in terms of [`sequence`] and [`map`] where:
16 ///
17 /// `(traverse f) ta = sequence ((map f) ta)`
18 ///
19 /// # Type Signature
20 ///
21 /// `forall a b. Traversable t, Applicative f => (a -> f b) -> t a -> f (t b)`
22 ///
23 /// # Parameters
24 ///
25 /// * `f`: A function that inputs the elements in the [`Traversable`] structure and outputs applicative computations for each.
26 /// * `ta`: A [`Traversable`] structure containing values.
27 ///
28 /// # Returns
29 ///
30 /// An [`Applicative`] containing the accumulated results of the computations.
31 ///
32 /// # Examples
33 ///
34 /// ```
35 /// use fp_library::{brands::{VecBrand, OptionBrand, RcFnBrand}, functions::traverse};
36 /// use std::rc::Rc;
37 ///
38 /// assert_eq!(
39 /// traverse::<RcFnBrand, VecBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(vec![1, 2, 3]),
40 /// Some(vec![2, 4, 6])
41 /// );
42 /// ```
43 fn traverse<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: Clone, B: 'a + Clone>(
44 f: ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
45 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<F, Apply0L1T<Self, B>>>
46 where
47 Apply0L1T<F, B>: Clone,
48 Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>>>: Clone,
49 Apply0L1T<Self, B>: 'a,
50 Apply0L1T<Self, Apply0L1T<F, B>>: 'a,
51 {
52 ClonableFnBrand::new(move |ta| {
53 Self::sequence::<ClonableFnBrand, F, B>(
54 map::<ClonableFnBrand, Self, _, Apply0L1T<F, B>>(f.clone())(ta),
55 )
56 })
57 }
58
59 /// Evaluate each computation in a [`Traversable`] structure and accumulate the results into an [`Applicative`] context.
60 ///
61 /// The default implementation of `sequence` is implemented in terms of [`traverse`] and [`identity`] where:
62 ///
63 /// `sequence = traverse identity`
64 ///
65 /// # Type Signature
66 ///
67 /// `forall a. Traversable t, Applicative f => t (f a) -> f (t a)`
68 ///
69 /// # Parameters
70 ///
71 /// * `t`: A [`Traversable`] structure containing [`Applicative`] computations.
72 ///
73 /// # Returns
74 ///
75 /// An [`Applicative`] containing the accumulated results of the computations.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use fp_library::{brands::{VecBrand, OptionBrand, RcFnBrand}, functions::sequence};
81 ///
82 /// assert_eq!(
83 /// sequence::<RcFnBrand, VecBrand, OptionBrand, i32>(vec![Some(1), Some(2), Some(3)]),
84 /// Some(vec![1, 2, 3])
85 /// );
86 /// ```
87 fn sequence<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: 'a + Clone>(
88 t: Apply0L1T<Self, Apply0L1T<F, A>>
89 ) -> Apply0L1T<F, Apply0L1T<Self, A>>
90 where
91 Apply0L1T<F, A>: 'a + Clone,
92 Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, A>>>: Clone,
93 Apply0L1T<Self, A>: 'a,
94 Apply0L1T<Self, Apply0L1T<F, A>>: 'a,
95 Apply0L1T<F, Apply0L1T<Self, A>>: 'a,
96 {
97 (Self::traverse::<ClonableFnBrand, F, _, A>(ClonableFnBrand::new(identity)))(t)
98 }
99}
100
101/// Map each element of the [`Traversable`] structure to a computation, evaluate those computations and combine the results into an [`Applicative`] context.
102///
103/// Free function version that dispatches to [the type class' associated function][`Traversable::traverse`].
104///
105/// The default implementation of `traverse` is implemented in terms of [`sequence`] and [`map`] where:
106///
107/// `(traverse f) ta = sequence ((map f) ta)`
108///
109/// # Type Signature
110///
111/// `forall a b. Traversable t, Applicative f => (a -> f b) -> t a -> f (t b)`
112///
113/// # Parameters
114///
115/// * `f`: A function that inputs the elements in the [`Traversable`] structure and outputs applicative computations for each.
116/// * `ta`: A [`Traversable`] structure containing values.
117///
118/// # Returns
119///
120/// An [`Applicative`] containing the accumulated results of the computations.
121///
122/// # Examples
123///
124/// ```
125/// use fp_library::{brands::{VecBrand, OptionBrand, RcFnBrand}, functions::traverse};
126/// use std::rc::Rc;
127///
128/// assert_eq!(
129/// traverse::<RcFnBrand, VecBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(vec![1, 2, 3]),
130/// Some(vec![2, 4, 6])
131/// );
132/// ```
133pub fn traverse<
134 'a,
135 ClonableFnBrand: 'a + ClonableFn,
136 Brand: Traversable,
137 F: Applicative,
138 A: Clone,
139 B: 'a + Clone,
140>(
141 f: ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
142) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Brand, A>, Apply0L1T<F, Apply0L1T<Brand, B>>>
143where
144 Apply0L1T<F, B>: Clone,
145 Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Brand, B>, Apply0L1T<Brand, B>>>: Clone,
146 Apply0L1T<Brand, B>: 'a,
147 Apply0L1T<Brand, Apply0L1T<F, B>>: 'a,
148{
149 Brand::traverse::<ClonableFnBrand, F, _, B>(f)
150}
151
152/// Evaluate each computation in a [`Traversable`] structure and accumulate the results into an [`Applicative`] context.
153///
154/// Free function version that dispatches to [the type class' associated function][`Traversable::sequence`].
155///
156/// The default implementation of `sequence` is implemented in terms of [`traverse`] and [`identity`] where:
157///
158/// `sequence = traverse identity`
159///
160/// # Type Signature
161///
162/// `forall a. Traversable t, Applicative f => t (f a) -> f (t a)`
163///
164/// # Parameters
165///
166/// * `t`: A [`Traversable`] structure containing [`Applicative`] computations.
167///
168/// # Returns
169///
170/// An [`Applicative`] containing the accumulated results of the computations.
171///
172/// # Examples
173///
174/// ```
175/// use fp_library::{brands::{VecBrand, OptionBrand, RcFnBrand}, functions::sequence};
176/// use std::rc::Rc;
177///
178/// assert_eq!(
179/// sequence::<RcFnBrand, VecBrand, OptionBrand, i32>(vec![Some(1), Some(2), Some(3)]),
180/// Some(vec![1, 2, 3])
181/// );
182/// ```
183pub fn sequence<
184 'a,
185 ClonableFnBrand: 'a + ClonableFn,
186 Brand: Traversable,
187 F: Applicative,
188 A: 'a + Clone,
189>(
190 t: Apply0L1T<Brand, Apply0L1T<F, A>>
191) -> Apply0L1T<F, Apply0L1T<Brand, A>>
192where
193 Apply0L1T<F, A>: 'a + Clone,
194 Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Brand, A>, Apply0L1T<Brand, A>>>: Clone,
195 Apply0L1T<Brand, A>: 'a,
196 Apply0L1T<Brand, Apply0L1T<F, A>>: 'a,
197 Apply0L1T<F, Apply0L1T<Brand, A>>: 'a,
198{
199 Brand::sequence::<ClonableFnBrand, F, A>(t)
200}