fp_library/classes/
traversable.rs

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