fp_library/classes/functor.rs
1use crate::{
2 classes::{ClonableFn, clonable_fn::ApplyFn},
3 hkt::{Apply0L1T, Kind0L1T},
4};
5
6/// A type class for types that can be mapped over.
7///
8/// A `Functor` represents a context or container that allows functions to be applied
9/// to values within that context without altering the structure of the context itself.
10///
11/// # Laws
12///
13/// `Functor` instances must satisfy the following laws:
14/// * Identity: `map(identity) = identity`.
15/// * Composition: `map(compose(f)(g)) = compose(map(f))(map(g))`.
16pub trait Functor: Kind0L1T {
17 /// Maps a function over the values in the functor context.
18 ///
19 /// # Type Signature
20 ///
21 /// `forall a b. Functor f => (a -> b) -> f a -> f b`
22 ///
23 /// # Parameters
24 ///
25 /// * `f`: A function to apply to the values within the functor context.
26 /// * `fa`: A functor containing values of type `A`.
27 ///
28 /// # Returns
29 ///
30 /// A functor containing values of type `B`.
31 fn map<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a, B: 'a>(
32 f: ApplyFn<'a, ClonableFnBrand, A, B>
33 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>>;
34}
35
36/// Maps a function over the values in the functor context.
37///
38/// Free function version that dispatches to [the type class' associated function][`Functor::map`].
39///
40/// # Type Signature
41///
42/// `forall a b. Functor f => (a -> b) -> f a -> f b`
43///
44/// # Parameters
45///
46/// * `f`: A function to apply to the values within the functor context.
47/// * `fa`: A functor containing values of type `A`.
48///
49/// # Returns
50///
51/// A functor containing values of type `B`.
52///
53/// # Examples
54///
55/// ```
56/// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::map};
57/// use std::rc::Rc;
58///
59/// assert_eq!(map::<RcFnBrand, OptionBrand, _, _>(Rc::new(|x: i32| x * 2))(Some(5)), Some(10));
60/// ```
61pub fn map<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Functor + ?Sized, A: 'a, B: 'a>(
62 f: ApplyFn<'a, ClonableFnBrand, A, B>
63) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Brand, A>, Apply0L1T<Brand, B>> {
64 Brand::map::<ClonableFnBrand, _, _>(f)
65}