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