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}