fp_library/classes/functor.rs
1//! Types that can be mapped over, allowing functions to be applied to values within a context.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! brands::*,
8//! functions::explicit::*,
9//! };
10//!
11//! let x = Some(5);
12//! let y = map::<OptionBrand, _, _, _, _>(|i| i * 2, x);
13//! assert_eq!(y, Some(10));
14//! ```
15
16#[fp_macros::document_module]
17mod inner {
18 use {
19 crate::kinds::*,
20 fp_macros::*,
21 };
22
23 /// A type class for types that can be mapped over.
24 ///
25 /// A `Functor` represents a context or container that allows functions to be applied
26 /// to values within that context without altering the structure of the context itself.
27 ///
28 /// ### Hierarchy Unification
29 ///
30 /// This trait inherits from [`Kind!(type Of<'a, A: 'a>: 'a;)`](crate::kinds::Kind_cdc7cd43dac7585f), ensuring that all functor
31 /// contexts satisfy the strict lifetime requirements where the type argument must
32 /// outlive the context's application lifetime.
33 ///
34 /// By explicitly requiring that the type parameter outlives the application lifetime `'a`,
35 /// we provide the compiler with the necessary guarantees to handle trait objects
36 /// (like `dyn Fn`) commonly used in functor implementations. This resolves potential
37 /// E0310 errors where the compiler cannot otherwise prove that captured variables in
38 /// closures satisfy the required lifetime bounds.
39 ///
40 /// ### Laws
41 ///
42 /// `Functor` instances must satisfy the following laws:
43 /// * Identity: `map(identity, fa) = fa`.
44 /// * Composition: `map(compose(f, g), fa) = map(f, map(g, fa))`.
45 #[document_examples]
46 ///
47 /// Functor laws for [`Option`]:
48 ///
49 /// ```
50 /// use fp_library::{
51 /// brands::*,
52 /// functions::{
53 /// explicit::map,
54 /// *,
55 /// },
56 /// };
57 ///
58 /// // Identity: map(identity, fa) = fa
59 /// assert_eq!(map::<OptionBrand, _, _, _, _>(identity, Some(5)), Some(5));
60 /// assert_eq!(map::<OptionBrand, _, _, _, _>(identity, None::<i32>), None);
61 ///
62 /// // Composition: map(compose(f, g), fa) = map(f, map(g, fa))
63 /// let f = |x: i32| x + 1;
64 /// let g = |x: i32| x * 2;
65 /// assert_eq!(
66 /// map::<OptionBrand, _, _, _, _>(compose(f, g), Some(5)),
67 /// map::<OptionBrand, _, _, _, _>(f, map::<OptionBrand, _, _, _, _>(g, Some(5))),
68 /// );
69 /// ```
70 ///
71 /// Functor laws for [`Vec`]:
72 ///
73 /// ```
74 /// use fp_library::{
75 /// brands::*,
76 /// functions::{
77 /// explicit::map,
78 /// *,
79 /// },
80 /// };
81 ///
82 /// // Identity: map(identity, fa) = fa
83 /// assert_eq!(map::<VecBrand, _, _, _, _>(identity, vec![1, 2, 3]), vec![1, 2, 3]);
84 ///
85 /// // Composition: map(compose(f, g), fa) = map(f, map(g, fa))
86 /// let f = |x: i32| x + 1;
87 /// let g = |x: i32| x * 2;
88 /// assert_eq!(
89 /// map::<VecBrand, _, _, _, _>(compose(f, g), vec![1, 2, 3]),
90 /// map::<VecBrand, _, _, _, _>(f, map::<VecBrand, _, _, _, _>(g, vec![1, 2, 3])),
91 /// );
92 /// ```
93 #[kind(type Of<'a, A: 'a>: 'a;)]
94 pub trait Functor {
95 /// Maps a function over the values in the functor context.
96 ///
97 /// This method applies a function to the value(s) inside the functor context, producing a new functor context with the transformed value(s).
98 #[document_signature]
99 ///
100 #[document_type_parameters(
101 "The lifetime of the values.",
102 "The type of the value(s) inside the functor.",
103 "The type of the result(s) of applying the function."
104 )]
105 ///
106 #[document_parameters(
107 "The function to apply to the value(s) inside the functor.",
108 "The functor instance containing the value(s)."
109 )]
110 ///
111 #[document_returns(
112 "A new functor instance containing the result(s) of applying the function."
113 )]
114 ///
115 #[document_examples]
116 ///
117 /// ```
118 /// use fp_library::{
119 /// brands::*,
120 /// functions::explicit::*,
121 /// };
122 ///
123 /// let x = Some(5);
124 /// let y = map::<OptionBrand, _, _, _, _>(|i| i * 2, x);
125 /// assert_eq!(y, Some(10));
126 /// ```
127 fn map<'a, A: 'a, B: 'a>(
128 f: impl Fn(A) -> B + 'a,
129 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
130 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
131 }
132}
133
134pub use inner::*;