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}