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}