fp_library/classes/traversable.rs
1use super::{applicative::Applicative, foldable::Foldable, functor::Functor};
2use crate::hkt::Apply1L1T;
3
4/// A type class for traversable functors.
5///
6/// `Traversable` functors can be traversed, which accumulates results and effects in some [`Applicative`] context.
7pub trait Traversable: Functor + Foldable {
8 /// Map each element of the [`Traversable`] structure to a computation, evaluate those computations and combine the results into an [`Applicative`] context.
9 ///
10 /// # Type Signature
11 ///
12 /// `forall a b f. (Traversable t, Applicative f) => (a -> f b, t a) -> f (t b)`
13 ///
14 /// # Parameters
15 ///
16 /// * `f`: The function to apply to each element, returning a value in an applicative context.
17 /// * `ta`: The traversable structure.
18 ///
19 /// # Returns
20 ///
21 /// The traversable structure wrapped in the applicative context.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// use fp_library::classes::traversable::Traversable;
27 /// use fp_library::brands::OptionBrand;
28 ///
29 /// let x = Some(5);
30 /// let y = OptionBrand::traverse::<OptionBrand, _, _, _>(|a| Some(a * 2), x);
31 /// assert_eq!(y, Some(Some(10)));
32 /// ```
33 fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
34 f: Func,
35 ta: Apply1L1T<'a, Self, A>,
36 ) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, B>>
37 where
38 Func: Fn(A) -> Apply1L1T<'a, F, B> + 'a,
39 Apply1L1T<'a, Self, B>: Clone;
40
41 /// Evaluate each computation in a [`Traversable`] structure and accumulate the results into an [`Applicative`] context.
42 ///
43 /// # Type Signature
44 ///
45 /// `forall a f. (Traversable t, Applicative f) => (t (f a)) -> f (t a)`
46 ///
47 /// # Parameters
48 ///
49 /// * `ta`: The traversable structure containing values in an applicative context.
50 ///
51 /// # Returns
52 ///
53 /// The traversable structure wrapped in the applicative context.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use fp_library::classes::traversable::Traversable;
59 /// use fp_library::brands::OptionBrand;
60 ///
61 /// let x = Some(Some(5));
62 /// let y = OptionBrand::sequence::<OptionBrand, _>(x);
63 /// assert_eq!(y, Some(Some(5)));
64 /// ```
65 fn sequence<'a, F: Applicative, A: 'a + Clone>(
66 ta: Apply1L1T<'a, Self, Apply1L1T<'a, F, A>>
67 ) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, A>>
68 where
69 Apply1L1T<'a, F, A>: Clone,
70 Apply1L1T<'a, Self, A>: Clone;
71}
72
73/// Map each element of the [`Traversable`] structure to a computation, evaluate those computations and combine the results into an [`Applicative`] context.
74///
75/// Free function version that dispatches to [the type class' associated function][`Traversable::traverse`].
76///
77/// # Type Signature
78///
79/// `forall a b f. (Traversable t, Applicative f) => (a -> f b, t a) -> f (t b)`
80///
81/// # Parameters
82///
83/// * `f`: The function to apply to each element, returning a value in an applicative context.
84/// * `ta`: The traversable structure.
85///
86/// # Returns
87///
88/// The traversable structure wrapped in the applicative context.
89///
90/// # Examples
91///
92/// ```
93/// use fp_library::classes::traversable::traverse;
94/// use fp_library::brands::OptionBrand;
95///
96/// let x = Some(5);
97/// let y = traverse::<OptionBrand, OptionBrand, _, _, _>(|a| Some(a * 2), x);
98/// assert_eq!(y, Some(Some(10)));
99/// ```
100pub fn traverse<'a, Brand: Traversable, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
101 f: Func,
102 ta: Apply1L1T<'a, Brand, A>,
103) -> Apply1L1T<'a, F, Apply1L1T<'a, Brand, B>>
104where
105 Func: Fn(A) -> Apply1L1T<'a, F, B> + 'a,
106 Apply1L1T<'a, Brand, B>: Clone,
107{
108 Brand::traverse::<F, A, B, Func>(f, ta)
109}
110
111/// Evaluate each computation in a [`Traversable`] structure and accumulate the results into an [`Applicative`] context.
112///
113/// Free function version that dispatches to [the type class' associated function][`Traversable::sequence`].
114///
115/// # Type Signature
116///
117/// `forall a f. (Traversable t, Applicative f) => (t (f a)) -> f (t a)`
118///
119/// # Parameters
120///
121/// * `ta`: The traversable structure containing values in an applicative context.
122///
123/// # Returns
124///
125/// The traversable structure wrapped in the applicative context.
126///
127/// # Examples
128///
129/// ```
130/// use fp_library::classes::traversable::sequence;
131/// use fp_library::brands::OptionBrand;
132///
133/// let x = Some(Some(5));
134/// let y = sequence::<OptionBrand, OptionBrand, _>(x);
135/// assert_eq!(y, Some(Some(5)));
136/// ```
137pub fn sequence<'a, Brand: Traversable, F: Applicative, A: 'a + Clone>(
138 ta: Apply1L1T<'a, Brand, Apply1L1T<'a, F, A>>
139) -> Apply1L1T<'a, F, Apply1L1T<'a, Brand, A>>
140where
141 Apply1L1T<'a, F, A>: Clone,
142 Apply1L1T<'a, Brand, A>: Clone,
143{
144 Brand::sequence::<F, A>(ta)
145}