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