fp_library/classes/
functor.rs

1use crate::hkt::{Apply1L1T, Kind1L1T};
2
3/// A type class for types that can be mapped over.
4///
5/// A `Functor` represents a context or container that allows functions to be applied
6/// to values within that context without altering the structure of the context itself.
7///
8/// # Laws
9///
10/// `Functor` instances must satisfy the following laws:
11/// * Identity: `map(identity, fa) = fa`.
12/// * Composition: `map(compose(f, g), fa) = map(f, map(g, fa))`.
13pub trait Functor: Kind1L1T {
14	/// Maps a function over the values in the functor context.
15	///
16	/// # Type Signature
17	///
18	/// `forall a b. Functor f => (a -> b, f a) -> f b`
19	///
20	/// # Parameters
21	///
22	/// * `f`: The function to apply to the value(s) inside the functor.
23	/// * `fa`: The functor instance containing the value(s).
24	///
25	/// # Returns
26	///
27	/// A new functor instance containing the result(s) of applying the function.
28	///
29	/// # Examples
30	///
31	/// ```
32	/// use fp_library::classes::functor::Functor;
33	/// use fp_library::brands::OptionBrand;
34	///
35	/// let x = Some(5);
36	/// let y = OptionBrand::map(|i| i * 2, x);
37	/// assert_eq!(y, Some(10));
38	/// ```
39	fn map<'a, A: 'a, B: 'a, F>(
40		f: F,
41		fa: Apply1L1T<'a, Self, A>,
42	) -> Apply1L1T<'a, Self, B>
43	where
44		F: Fn(A) -> B + 'a;
45}
46
47/// Maps a function over the values in the functor context.
48///
49/// Free function version that dispatches to [the type class' associated function][`Functor::map`].
50///
51/// # Type Signature
52///
53/// `forall a b. Functor f => (a -> b, f a) -> f b`
54///
55/// # Parameters
56///
57/// * `f`: The function to apply to the value(s) inside the functor.
58/// * `fa`: The functor instance containing the value(s).
59///
60/// # Returns
61///
62/// A new functor instance containing the result(s) of applying the function.
63///
64/// # Examples
65///
66/// ```
67/// use fp_library::classes::functor::map;
68/// use fp_library::brands::OptionBrand;
69///
70/// let x = Some(5);
71/// let y = map::<OptionBrand, _, _, _>(|i| i * 2, x);
72/// assert_eq!(y, Some(10));
73/// ```
74pub fn map<'a, Brand: Functor, A: 'a, B: 'a, F>(
75	f: F,
76	fa: Apply1L1T<'a, Brand, A>,
77) -> Apply1L1T<'a, Brand, B>
78where
79	F: Fn(A) -> B + 'a,
80{
81	Brand::map(f, fa)
82}