fp_library/typeclasses/functor.rs
1use crate::hkt::{Apply, Kind};
2
3/// A typeclass 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/// Functors must satisfy the following laws:
11/// * Identity: `map(identity) = identity`.
12/// * Composition: `map(f . g) = map(f) . map(g)`.
13pub trait Functor {
14 /// Maps a function over the values in the functor context.
15 ///
16 /// # Type Signature
17 ///
18 /// `forall f a b. Functor f => (a -> b) -> f a -> f b`
19 ///
20 /// # Parameters
21 ///
22 /// * `f`: A function to apply to the values within the functor context.
23 /// * `fa`: A functor containing values of type `A`.
24 ///
25 /// # Returns
26 ///
27 /// A functor containing values of type `B`.
28 fn map<F, A, B>(f: F) -> impl Fn(Apply<Self, (A,)>) -> Apply<Self, (B,)>
29 where
30 Self: Kind<(A,)> + Kind<(B,)>,
31 F: Fn(A) -> B;
32}
33
34/// Maps a function over the values in the functor context.
35///
36/// Free function version that dispatches to [the typeclass method][`Functor::map`].
37///
38/// # Type Signature
39///
40/// `forall f a b. Functor f => (a -> b) -> f a -> f b`
41///
42/// # Parameters
43///
44/// * `f`: A function to apply to the values within the functor context.
45/// * `fa`: A functor containing values of type `A`.
46///
47/// # Returns
48///
49/// A functor containing values of type `B`.
50///
51/// # Examples
52///
53/// ```
54/// use fp_library::{brands::OptionBrand, functions::map};
55///
56/// assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x * 2)(Some(5)), Some(10));
57/// ```
58pub fn map<Brand, F, A, B>(f: F) -> impl Fn(Apply<Brand, (A,)>) -> Apply<Brand, (B,)>
59where
60 Brand: Kind<(A,)> + Kind<(B,)> + Functor,
61 F: Fn(A) -> B,
62{
63 Brand::map(f)
64}