Skip to main content

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::*;