Skip to main content

fp_library/dispatch/
map_first.rs

1//! Dispatch for [`Bifunctor::map_first`](crate::classes::Bifunctor::map_first) and
2//! [`RefBifunctor::ref_map_first`](crate::classes::RefBifunctor::ref_map_first).
3//!
4//! Provides the [`MapFirstDispatch`] trait and a unified [`explicit::map_first`]
5//! free function that routes to the appropriate trait method based on the
6//! closure's argument type.
7//!
8//! Corresponds to `lmap` in both Haskell and PureScript.
9//!
10//! ### Examples
11//!
12//! ```
13//! use fp_library::{
14//! 	brands::*,
15//! 	functions::explicit::*,
16//! };
17//!
18//! // Owned: dispatches to Bifunctor::map_first
19//! let x = Result::<i32, i32>::Err(5);
20//! let y = map_first::<ResultBrand, _, _, _, _, _>(|e| e * 2, x);
21//! assert_eq!(y, Err(10));
22//!
23//! // By-ref: dispatches to RefBifunctor::ref_map_first
24//! let x = Result::<i32, i32>::Err(5);
25//! let y = map_first::<ResultBrand, _, _, _, _, _>(|e: &i32| *e * 2, &x);
26//! assert_eq!(y, Err(10));
27//! ```
28
29#[fp_macros::document_module]
30pub(crate) mod inner {
31	use {
32		crate::{
33			classes::{
34				Bifunctor,
35				RefBifunctor,
36			},
37			dispatch::{
38				Ref,
39				Val,
40			},
41			kinds::*,
42		},
43		fp_macros::*,
44	};
45
46	/// Trait that routes a map_first operation to the appropriate type class method.
47	///
48	/// The `Marker` type parameter is inferred from the closure's argument type:
49	/// `Fn(A) -> B` resolves to [`Val`](crate::dispatch::Val),
50	/// `Fn(&A) -> B` resolves to [`Ref`](crate::dispatch::Ref).
51	/// The `FA` type parameter is inferred from the container argument: owned
52	/// for Val dispatch, borrowed for Ref dispatch.
53	#[document_type_parameters(
54		"The lifetime of the values.",
55		"The brand of the bifunctor.",
56		"The type of the first value.",
57		"The type of the first result.",
58		"The type of the second value.",
59		"The container type (owned or borrowed), inferred from the argument.",
60		"Dispatch marker type, inferred automatically."
61	)]
62	#[document_parameters("The closure implementing this dispatch.")]
63	pub trait MapFirstDispatch<'a, Brand: Kind_266801a817966495, A: 'a, B: 'a, C: 'a, FA, Marker> {
64		/// Perform the dispatched map_first operation.
65		#[document_signature]
66		#[document_parameters("The bifunctor value.")]
67		#[document_returns("A new bifunctor with the first value transformed.")]
68		#[document_examples]
69		///
70		/// ```
71		/// use fp_library::{
72		/// 	brands::*,
73		/// 	functions::explicit::*,
74		/// };
75		/// let result = map_first::<ResultBrand, _, _, _, _, _>(|e| e + 1, Err::<i32, i32>(5));
76		/// assert_eq!(result, Err(6));
77		/// ```
78		fn dispatch(
79			self,
80			fa: FA,
81		) -> Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, C>);
82	}
83
84	// -- Val: Fn(A) -> B -> Bifunctor::map_first --
85
86	/// Routes `Fn(A) -> B` closures to [`Bifunctor::map_first`].
87	#[document_type_parameters(
88		"The lifetime of the values.",
89		"The brand of the bifunctor.",
90		"The type of the first value.",
91		"The type of the first result.",
92		"The type of the second value.",
93		"The closure type."
94	)]
95	#[document_parameters("The closure that takes owned values.")]
96	impl<'a, Brand, A, B, C, F>
97		MapFirstDispatch<
98			'a,
99			Brand,
100			A,
101			B,
102			C,
103			Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
104			Val,
105		> for F
106	where
107		Brand: Bifunctor,
108		A: 'a,
109		B: 'a,
110		C: 'a,
111		F: Fn(A) -> B + 'a,
112	{
113		#[document_signature]
114		#[document_parameters("The bifunctor value.")]
115		#[document_returns("A new bifunctor with the first value transformed.")]
116		#[document_examples]
117		///
118		/// ```
119		/// use fp_library::{
120		/// 	brands::*,
121		/// 	functions::explicit::*,
122		/// };
123		/// let result = map_first::<ResultBrand, _, _, _, _, _>(|e| e + 1, Err::<i32, i32>(5));
124		/// assert_eq!(result, Err(6));
125		/// ```
126		fn dispatch(
127			self,
128			fa: Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
129		) -> Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, C>) {
130			Brand::map_first(self, fa)
131		}
132	}
133
134	// -- Ref: Fn(&A) -> B -> RefBifunctor::ref_map_first --
135
136	/// Routes `Fn(&A) -> B` closures to [`RefBifunctor::ref_map_first`].
137	///
138	/// The container must be passed by reference (`&p`).
139	#[document_type_parameters(
140		"The lifetime of the values.",
141		"The borrow lifetime.",
142		"The brand of the bifunctor.",
143		"The type of the first value.",
144		"The type of the first result.",
145		"The type of the second value (must be Clone).",
146		"The closure type."
147	)]
148	#[document_parameters("The closure that takes references.")]
149	impl<'a, 'b, Brand, A, B, C, F>
150		MapFirstDispatch<
151			'a,
152			Brand,
153			A,
154			B,
155			C,
156			&'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
157			Ref,
158		> for F
159	where
160		Brand: RefBifunctor,
161		A: 'a,
162		B: 'a,
163		C: Clone + 'a,
164		F: Fn(&A) -> B + 'a,
165	{
166		#[document_signature]
167		#[document_parameters("A reference to the bifunctor value.")]
168		#[document_returns("A new bifunctor with the first value transformed.")]
169		#[document_examples]
170		///
171		/// ```
172		/// use fp_library::{
173		/// 	brands::*,
174		/// 	functions::explicit::*,
175		/// };
176		/// let x = Err::<i32, i32>(5);
177		/// let result = map_first::<ResultBrand, _, _, _, _, _>(|e: &i32| *e + 1, &x);
178		/// assert_eq!(result, Err(6));
179		/// ```
180		fn dispatch(
181			self,
182			fa: &'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, C>),
183		) -> Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, C>) {
184			Brand::ref_map_first(self, fa)
185		}
186	}
187
188	// -- Inference wrapper --
189
190	/// Maps a function over the first type argument of a bifunctor, inferring the
191	/// brand from the container type.
192	///
193	/// Corresponds to `lmap` in both Haskell and PureScript.
194	///
195	/// The `Brand` type parameter is inferred from the concrete type of `p` via
196	/// the `InferableBrand` trait. Both owned and borrowed containers are
197	/// supported.
198	///
199	/// For types that need an explicit brand, use
200	/// [`explicit::map_first`](crate::functions::explicit::map_first) with a turbofish.
201	#[document_signature]
202	///
203	#[document_type_parameters(
204		"The lifetime of the values.",
205		"The container type (owned or borrowed). Brand is inferred from this.",
206		"The type of the first value.",
207		"The type of the first result.",
208		"The type of the second value.",
209		"The brand, inferred via InferableBrand from FA and the element types."
210	)]
211	///
212	#[document_parameters(
213		"The function to apply to the first value.",
214		"The bifunctor value (owned or borrowed)."
215	)]
216	///
217	#[document_returns("A new bifunctor with the first value transformed.")]
218	#[document_examples]
219	///
220	/// ```
221	/// use fp_library::functions::*;
222	///
223	/// // Brand inferred from Result<i32, String>
224	/// let x: Result<String, i32> = Err(5);
225	/// let y = map_first(|e| e * 2, x);
226	/// assert_eq!(y, Err(10));
227	/// ```
228	pub fn map_first<'a, FA, A: 'a, B: 'a, C: 'a, Brand>(
229		f: impl MapFirstDispatch<
230			'a,
231			Brand,
232			A,
233			B,
234			C,
235			FA,
236			<FA as InferableBrand_266801a817966495<'a, Brand, A, C>>::Marker,
237		>,
238		p: FA,
239	) -> Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, C>)
240	where
241		Brand: Kind_266801a817966495,
242		FA: InferableBrand_266801a817966495<'a, Brand, A, C>, {
243		f.dispatch(p)
244	}
245
246	// -- Explicit dispatch free function --
247
248	/// Explicit dispatch functions requiring a Brand turbofish.
249	///
250	/// For most use cases, prefer the inference-enabled wrappers from
251	/// [`functions`](crate::functions).
252	pub mod explicit {
253		use super::*;
254
255		/// Maps a function over the first type argument of a bifunctor.
256		///
257		/// Corresponds to `lmap` in both Haskell and PureScript.
258		///
259		/// Dispatches to either [`Bifunctor::map_first`] or
260		/// [`RefBifunctor::ref_map_first`] based on the closure's argument type.
261		///
262		/// The `Marker` and `FA` type parameters are inferred automatically by the
263		/// compiler. Callers write `map_first::<Brand, _, _, _, _>(...)` and never
264		/// need to specify `Marker` or `FA` explicitly.
265		#[document_signature]
266		///
267		#[document_type_parameters(
268			"The lifetime of the values.",
269			"The brand of the bifunctor.",
270			"The type of the first value.",
271			"The type of the first result.",
272			"The type of the second value.",
273			"The container type (owned or borrowed), inferred from the argument.",
274			"Dispatch marker type, inferred automatically."
275		)]
276		///
277		#[document_parameters(
278			"The function to apply to the first value.",
279			"The bifunctor value (owned for Val, borrowed for Ref)."
280		)]
281		///
282		#[document_returns("A new bifunctor with the first value transformed.")]
283		#[document_examples]
284		///
285		/// ```
286		/// use fp_library::{
287		/// 	brands::*,
288		/// 	functions::explicit::*,
289		/// };
290		///
291		/// // Owned
292		/// let x = Result::<i32, i32>::Err(5);
293		/// let y = map_first::<ResultBrand, _, _, _, _, _>(|e| e * 2, x);
294		/// assert_eq!(y, Err(10));
295		///
296		/// // By-ref
297		/// let x = Result::<i32, i32>::Err(5);
298		/// let y = map_first::<ResultBrand, _, _, _, _, _>(|e: &i32| *e * 2, &x);
299		/// assert_eq!(y, Err(10));
300		/// ```
301		pub fn map_first<'a, Brand: Kind_266801a817966495, A: 'a, B: 'a, C: 'a, FA, Marker>(
302			f: impl MapFirstDispatch<'a, Brand, A, B, C, FA, Marker>,
303			p: FA,
304		) -> Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, B, C>) {
305			f.dispatch(p)
306		}
307	}
308}
309
310pub use inner::*;