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