Skip to main content

fp_library/dispatch/
semimonad.rs

1//! Dispatch for semimonad operations:
2//! [`Semimonad`](crate::classes::Semimonad) and
3//! [`RefSemimonad`](crate::classes::RefSemimonad).
4//!
5//! Provides the following dispatch traits and unified free functions:
6//!
7//! - [`BindDispatch`] + [`explicit::bind`], [`explicit::bind_flipped`]
8//! - [`ComposeKleisliDispatch`] + [`compose_kleisli`], [`compose_kleisli_flipped`]
9//! - [`JoinDispatch`] + [`explicit::join`]
10//!
11//! Each routes to the appropriate trait method based on the closure's argument
12//! type.
13//!
14//! ### Examples
15//!
16//! ```
17//! use fp_library::{
18//! 	brands::*,
19//! 	functions::explicit::*,
20//! 	types::*,
21//! };
22//!
23//! // Owned: dispatches to Semimonad::bind
24//! let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
25//! assert_eq!(result, Some(10));
26//!
27//! // By-ref: dispatches to RefSemimonad::ref_bind
28//! let lazy = RcLazy::pure(5);
29//! let result = bind::<LazyBrand<RcLazyConfig>, _, _, _, _>(&lazy, |x: &i32| {
30//! 	Lazy::<_, RcLazyConfig>::new({
31//! 		let v = *x;
32//! 		move || v * 2
33//! 	})
34//! });
35//! assert_eq!(*result.evaluate(), 10);
36//! ```
37
38#[fp_macros::document_module]
39pub(crate) mod inner {
40	use {
41		crate::{
42			classes::{
43				RefSemimonad,
44				Semimonad,
45			},
46			dispatch::{
47				Ref,
48				Val,
49			},
50			kinds::*,
51		},
52		fp_macros::*,
53	};
54
55	/// Trait that routes a bind operation to the appropriate type class method.
56	///
57	/// The `Marker` type parameter is inferred from the closure's argument type:
58	/// `Fn(A) -> Of<B>` resolves to [`Val`](crate::dispatch::Val),
59	/// `Fn(&A) -> Of<B>` resolves to [`Ref`](crate::dispatch::Ref).
60	/// The `FA` type parameter is inferred from the container argument: owned
61	/// for Val dispatch, borrowed for Ref dispatch.
62	#[document_type_parameters(
63		"The lifetime of the values.",
64		"The brand of the monad.",
65		"The type of the value inside the monad.",
66		"The type of the result.",
67		"The container type (owned or borrowed), inferred from the argument.",
68		"Dispatch marker type, inferred automatically."
69	)]
70	#[document_parameters("The closure implementing this dispatch.")]
71	pub trait BindDispatch<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, FA, Marker> {
72		/// Perform the dispatched bind operation.
73		#[document_signature]
74		#[document_parameters("The monadic value.")]
75		#[document_returns("The result of binding.")]
76		#[document_examples]
77		///
78		/// ```
79		/// use fp_library::{
80		/// 	brands::*,
81		/// 	functions::explicit::*,
82		/// };
83		/// let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
84		/// assert_eq!(result, Some(10));
85		/// ```
86		fn dispatch(
87			self,
88			ma: FA,
89		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
90	}
91
92	/// Routes `Fn(A) -> Of<B>` closures to [`Semimonad::bind`].
93	#[document_type_parameters(
94		"The lifetime.",
95		"The brand.",
96		"The input type.",
97		"The output type.",
98		"The closure type."
99	)]
100	#[document_parameters("The closure that takes owned values.")]
101	impl<'a, Brand, A, B, F>
102		BindDispatch<
103			'a,
104			Brand,
105			A,
106			B,
107			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
108			Val,
109		> for F
110	where
111		Brand: Semimonad,
112		A: 'a,
113		B: 'a,
114		F: Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
115	{
116		#[document_signature]
117		#[document_parameters("The monadic value.")]
118		#[document_returns("The result of binding.")]
119		#[document_examples]
120		///
121		/// ```
122		/// use fp_library::{
123		/// 	brands::*,
124		/// 	functions::explicit::*,
125		/// };
126		/// let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
127		/// assert_eq!(result, Some(10));
128		/// ```
129		fn dispatch(
130			self,
131			ma: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
132		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
133			Brand::bind(ma, self)
134		}
135	}
136
137	/// Routes `Fn(&A) -> Of<B>` closures to [`RefSemimonad::ref_bind`].
138	///
139	/// The container must be passed by reference (`&ma`).
140	#[document_type_parameters(
141		"The lifetime.",
142		"The borrow lifetime.",
143		"The brand.",
144		"The input type.",
145		"The output type.",
146		"The closure type."
147	)]
148	#[document_parameters("The closure that takes references.")]
149	impl<'a, 'b, Brand, A, B, F>
150		BindDispatch<
151			'a,
152			Brand,
153			A,
154			B,
155			&'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
156			Ref,
157		> for F
158	where
159		Brand: RefSemimonad,
160		A: 'a,
161		B: 'a,
162		F: Fn(&A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
163	{
164		#[document_signature]
165		#[document_parameters("A reference to the monadic value.")]
166		#[document_returns("The result of binding.")]
167		#[document_examples]
168		///
169		/// ```
170		/// use fp_library::{
171		/// 	brands::*,
172		/// 	functions::explicit::*,
173		/// 	types::*,
174		/// };
175		/// let lazy = RcLazy::pure(5);
176		/// let result = bind::<LazyBrand<RcLazyConfig>, _, _, _, _>(&lazy, |x: &i32| {
177		/// 	Lazy::<_, RcLazyConfig>::new({
178		/// 		let v = *x;
179		/// 		move || v * 2
180		/// 	})
181		/// });
182		/// assert_eq!(*result.evaluate(), 10);
183		/// ```
184		fn dispatch(
185			self,
186			ma: &'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
187		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
188			Brand::ref_bind(ma, self)
189		}
190	}
191
192	// -- ComposeKleisliDispatch --
193
194	/// Dispatch trait for Kleisli composition.
195	///
196	/// Routes `Fn(A) -> Of<B>` closures to [`Semimonad::bind`]-based composition
197	/// and `Fn(&A) -> Of<B>` closures to [`RefSemimonad::ref_bind`]-based composition.
198	#[document_type_parameters(
199		"The lifetime of the values.",
200		"The higher-kinded type brand.",
201		"The input type.",
202		"The intermediate type.",
203		"The output type.",
204		"Marker type (`Val` or `Ref`), inferred from the closures."
205	)]
206	#[document_parameters("The closure pair implementing this dispatch.")]
207	pub trait ComposeKleisliDispatch<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, C: 'a, Marker>
208	{
209		/// Performs the dispatched Kleisli composition.
210		#[document_signature]
211		#[document_parameters("The input value.")]
212		#[document_returns("The result of composing f then g applied to the input.")]
213		#[document_examples]
214		///
215		/// ```
216		/// use fp_library::{
217		/// 	brands::*,
218		/// 	functions::*,
219		/// };
220		/// let result =
221		/// 	compose_kleisli::<OptionBrand, _, _, _, _>((|x: i32| Some(x + 1), |y: i32| Some(y * 2)), 5);
222		/// assert_eq!(result, Some(12));
223		/// ```
224		fn dispatch(
225			self,
226			a: A,
227		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>);
228	}
229
230	#[document_type_parameters(
231		"The lifetime of the values.",
232		"The higher-kinded type brand.",
233		"The input type.",
234		"The intermediate type.",
235		"The output type.",
236		"The first closure type.",
237		"The second closure type."
238	)]
239	#[document_parameters("The closure pair.")]
240	impl<'a, Brand, A, B, C, F, G> ComposeKleisliDispatch<'a, Brand, A, B, C, Val> for (F, G)
241	where
242		Brand: Semimonad,
243		A: 'a,
244		B: 'a,
245		C: 'a,
246		F: Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
247		G: Fn(B) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
248	{
249		#[document_signature]
250		#[document_parameters("The input value.")]
251		#[document_returns("The composed result.")]
252		#[document_examples]
253		///
254		/// ```
255		/// use fp_library::{
256		/// 	brands::*,
257		/// 	functions::*,
258		/// };
259		/// let result =
260		/// 	compose_kleisli::<OptionBrand, _, _, _, _>((|x: i32| Some(x + 1), |y: i32| Some(y * 2)), 5);
261		/// assert_eq!(result, Some(12));
262		/// ```
263		fn dispatch(
264			self,
265			a: A,
266		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
267			Brand::bind(self.0(a), self.1)
268		}
269	}
270
271	#[document_type_parameters(
272		"The lifetime of the values.",
273		"The higher-kinded type brand.",
274		"The input type.",
275		"The intermediate type.",
276		"The output type.",
277		"The first closure type.",
278		"The second closure type."
279	)]
280	#[document_parameters("The closure pair.")]
281	impl<'a, Brand, A, B, C, F, G> ComposeKleisliDispatch<'a, Brand, A, B, C, Ref> for (F, G)
282	where
283		Brand: RefSemimonad,
284		A: 'a,
285		B: 'a,
286		C: 'a,
287		F: Fn(&A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
288		G: Fn(&B) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
289	{
290		#[document_signature]
291		#[document_parameters("The input value.")]
292		#[document_returns("The composed result.")]
293		#[document_examples]
294		///
295		/// ```
296		/// use fp_library::{
297		/// 	brands::*,
298		/// 	functions::*,
299		/// 	types::*,
300		/// };
301		/// let result = compose_kleisli::<LazyBrand<RcLazyConfig>, _, _, _, _>(
302		/// 	(
303		/// 		|x: &i32| {
304		/// 			let v = *x + 1;
305		/// 			RcLazy::new(move || v)
306		/// 		},
307		/// 		|y: &i32| {
308		/// 			let v = *y * 2;
309		/// 			RcLazy::new(move || v)
310		/// 		},
311		/// 	),
312		/// 	5,
313		/// );
314		/// assert_eq!(*result.evaluate(), 12);
315		/// ```
316		fn dispatch(
317			self,
318			a: A,
319		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
320			Brand::ref_bind(&(self.0(&a)), self.1)
321		}
322	}
323
324	/// Composes two Kleisli arrows (f then g).
325	///
326	/// Dispatches to [`Semimonad::bind`] or [`RefSemimonad::ref_bind`]
327	/// based on whether the closures take `A`/`B` or `&A`/`&B`.
328	#[document_signature]
329	///
330	#[document_type_parameters(
331		"The lifetime of the values.",
332		"The higher-kinded type brand.",
333		"The input type.",
334		"The intermediate type.",
335		"The output type.",
336		"Marker type, inferred from the closures."
337	)]
338	///
339	#[document_parameters("A tuple of (first arrow, second arrow).", "The input value.")]
340	///
341	#[document_returns("The result of applying f then g.")]
342	#[document_examples]
343	///
344	/// ```
345	/// use fp_library::{
346	/// 	brands::*,
347	/// 	functions::*,
348	/// };
349	///
350	/// let result =
351	/// 	compose_kleisli::<OptionBrand, _, _, _, _>((|x: i32| Some(x + 1), |y: i32| Some(y * 2)), 5);
352	/// assert_eq!(result, Some(12));
353	/// ```
354	pub fn compose_kleisli<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, C: 'a, Marker>(
355		fg: impl ComposeKleisliDispatch<'a, Brand, A, B, C, Marker>,
356		a: A,
357	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
358		fg.dispatch(a)
359	}
360
361	/// Composes two Kleisli arrows (g then f), flipped argument order.
362	///
363	/// Dispatches to [`Semimonad::bind`] or [`RefSemimonad::ref_bind`]
364	/// based on whether the closures take `B`/`A` or `&B`/`&A`.
365	/// Delegates to [`ComposeKleisliDispatch`] by swapping the tuple
366	/// elements.
367	#[document_signature]
368	///
369	#[document_type_parameters(
370		"The lifetime of the values.",
371		"The higher-kinded type brand.",
372		"The input type.",
373		"The intermediate type.",
374		"The output type.",
375		"The second arrow type (`B -> Of<C>`).",
376		"The first arrow type (`A -> Of<B>`).",
377		"Marker type, inferred from the closures."
378	)]
379	///
380	#[document_parameters("A tuple of (second arrow, first arrow).", "The input value.")]
381	///
382	#[document_returns("The result of applying g then f.")]
383	#[document_examples]
384	///
385	/// ```
386	/// use fp_library::{
387	/// 	brands::*,
388	/// 	functions::*,
389	/// };
390	///
391	/// let result = compose_kleisli_flipped::<OptionBrand, _, _, _, _, _, _>(
392	/// 	(|y: i32| Some(y * 2), |x: i32| Some(x + 1)),
393	/// 	5,
394	/// );
395	/// assert_eq!(result, Some(12));
396	/// ```
397	pub fn compose_kleisli_flipped<
398		'a,
399		Brand: Kind_cdc7cd43dac7585f,
400		A: 'a,
401		B: 'a,
402		C: 'a,
403		F,
404		G,
405		Marker,
406	>(
407		gf: (F, G),
408		a: A,
409	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
410	where
411		(G, F): ComposeKleisliDispatch<'a, Brand, A, B, C, Marker>, {
412		ComposeKleisliDispatch::dispatch((gf.1, gf.0), a)
413	}
414
415	// -- JoinDispatch --
416
417	/// Trait that routes a join operation to the appropriate type class method.
418	///
419	/// The `Marker` type parameter is an implementation detail resolved by
420	/// the compiler from the container type; callers never specify it directly.
421	/// Owned containers resolve to [`Val`], borrowed containers resolve to [`Ref`].
422	#[document_type_parameters(
423		"The lifetime of the values.",
424		"The brand of the monad.",
425		"The type of the value(s) inside the inner layer.",
426		"Dispatch marker type, inferred automatically. Either [`Val`](crate::dispatch::Val) or [`Ref`](crate::dispatch::Ref)."
427	)]
428	#[document_parameters("The container implementing this dispatch.")]
429	pub trait JoinDispatch<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, Marker> {
430		/// Perform the dispatched join operation.
431		#[document_signature]
432		///
433		#[document_returns("A container with one layer of nesting removed.")]
434		#[document_examples]
435		///
436		/// ```
437		/// use fp_library::{
438		/// 	brands::*,
439		/// 	functions::explicit::*,
440		/// };
441		///
442		/// let result = join::<OptionBrand, _, _>(Some(Some(5)));
443		/// assert_eq!(result, Some(5));
444		/// ```
445		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
446	}
447
448	// -- Val: owned container -> Semimonad::bind(id) --
449
450	/// Routes owned containers to [`Semimonad::bind`] with identity.
451	#[document_type_parameters("The lifetime.", "The brand.", "The inner element type.")]
452	#[document_parameters("The nested monadic value.")]
453	impl<'a, Brand, A> JoinDispatch<'a, Brand, A, Val> for Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
454	where
455		Brand: Semimonad,
456		A: 'a,
457	{
458		#[document_signature]
459		///
460		#[document_returns("A container with one layer of nesting removed.")]
461		#[document_examples]
462		///
463		/// ```
464		/// use fp_library::{
465		/// 	brands::*,
466		/// 	functions::explicit::*,
467		/// };
468		///
469		/// let result = join::<OptionBrand, _, _>(Some(Some(5)));
470		/// assert_eq!(result, Some(5));
471		/// ```
472		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
473			Brand::bind(self, |ma| ma)
474		}
475	}
476
477	// -- Ref: borrowed container -> RefSemimonad::ref_bind(clone) --
478
479	/// Routes borrowed containers to [`RefSemimonad::ref_bind`] with clone.
480	#[document_type_parameters("The lifetime.", "The brand.", "The inner element type.")]
481	#[document_parameters("A reference to the nested monadic value.")]
482	impl<'a, Brand, A> JoinDispatch<'a, Brand, A, Ref> for &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
483	where
484		Brand: RefSemimonad,
485		A: 'a,
486		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
487	{
488		#[document_signature]
489		///
490		#[document_returns("A container with one layer of nesting removed.")]
491		#[document_examples]
492		///
493		/// ```
494		/// use fp_library::{
495		/// 	brands::*,
496		/// 	functions::explicit::*,
497		/// };
498		///
499		/// let x = Some(Some(5));
500		/// let result = join::<OptionBrand, _, _>(&x);
501		/// assert_eq!(result, Some(5));
502		/// ```
503		fn dispatch(self) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
504			Brand::ref_bind(self, |ma| ma.clone())
505		}
506	}
507
508	// -- Inference wrappers --
509
510	/// Sequences a monadic computation, inferring the brand from the container type.
511	///
512	/// The `Brand` type parameter is inferred from the concrete type of `ma`
513	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
514	///
515	/// For types with multiple brands, use
516	/// [`explicit::bind`](crate::functions::explicit::bind) with a turbofish.
517	#[document_signature]
518	///
519	#[document_type_parameters(
520		"The lifetime of the values.",
521		"The container type (owned or borrowed). Brand is inferred from this.",
522		"The type of the value inside the monad.",
523		"The type of the result.",
524		"Dispatch marker type, inferred automatically."
525	)]
526	///
527	#[document_parameters(
528		"The monadic value (owned for Val, borrowed for Ref).",
529		"The function to apply to the value."
530	)]
531	///
532	#[document_returns("The result of sequencing the computation.")]
533	#[document_examples]
534	///
535	/// ```
536	/// use fp_library::functions::*;
537	///
538	/// let result = bind(Some(5), |x: i32| Some(x * 2));
539	/// assert_eq!(result, Some(10));
540	/// ```
541	pub fn bind<'a, FA, A: 'a, B: 'a, Marker>(
542		ma: FA,
543		f: impl BindDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, A, B, FA, Marker>,
544	) -> Apply!(<<FA as InferableBrand!(type Of<'a, A: 'a>: 'a;)>::Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
545	where
546		FA: InferableBrand_cdc7cd43dac7585f, {
547		f.dispatch(ma)
548	}
549
550	/// Sequences a monadic computation (flipped argument order), inferring the brand
551	/// from the container type.
552	///
553	/// The `Brand` type parameter is inferred from the concrete type of `ma`
554	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
555	///
556	/// For types with multiple brands, use
557	/// [`explicit::bind_flipped`](crate::functions::explicit::bind_flipped) with a turbofish.
558	#[document_signature]
559	///
560	#[document_type_parameters(
561		"The lifetime of the values.",
562		"The container type (owned or borrowed). Brand is inferred from this.",
563		"The input element type.",
564		"The output element type.",
565		"Dispatch marker type, inferred automatically."
566	)]
567	///
568	#[document_parameters(
569		"The function to apply to each element.",
570		"The monadic value (owned for Val, borrowed for Ref)."
571	)]
572	///
573	#[document_returns("The result of binding the function over the value.")]
574	#[document_examples]
575	///
576	/// ```
577	/// use fp_library::functions::*;
578	///
579	/// let result = bind_flipped(|x: i32| Some(x * 2), Some(5));
580	/// assert_eq!(result, Some(10));
581	/// ```
582	pub fn bind_flipped<'a, FA, A: 'a, B: 'a, Marker>(
583		f: impl BindDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, A, B, FA, Marker>,
584		ma: FA,
585	) -> Apply!(<<FA as InferableBrand!(type Of<'a, A: 'a>: 'a;)>::Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
586	where
587		FA: InferableBrand_cdc7cd43dac7585f, {
588		f.dispatch(ma)
589	}
590
591	/// Removes one layer of monadic nesting, inferring the brand from the container type.
592	///
593	/// The `Brand` type parameter is inferred from the concrete type of `mma`
594	/// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
595	///
596	/// For types with multiple brands, use
597	/// [`explicit::join`](crate::functions::explicit::join) with a turbofish.
598	#[document_signature]
599	///
600	#[document_type_parameters(
601		"The lifetime of the values.",
602		"The container type (owned or borrowed). Brand is inferred from this.",
603		"The type of the value(s) inside the inner layer.",
604		"Dispatch marker type, inferred automatically."
605	)]
606	///
607	#[document_parameters("The nested monadic value (owned or borrowed).")]
608	///
609	#[document_returns("A container with one layer of nesting removed.")]
610	#[document_examples]
611	///
612	/// ```
613	/// use fp_library::functions::*;
614	///
615	/// assert_eq!(join(Some(Some(5))), Some(5));
616	///
617	/// let x = Some(Some(5));
618	/// assert_eq!(join(&x), Some(5));
619	/// ```
620	pub fn join<'a, FA, A: 'a, Marker>(
621		mma: FA
622	) -> <<FA as InferableBrand_cdc7cd43dac7585f>::Brand as Kind_cdc7cd43dac7585f>::Of<'a, A>
623	where
624		FA: InferableBrand_cdc7cd43dac7585f
625			+ JoinDispatch<'a, <FA as InferableBrand_cdc7cd43dac7585f>::Brand, A, Marker>, {
626		mma.dispatch()
627	}
628
629	// -- Explicit dispatch free functions --
630
631	/// Explicit dispatch functions requiring a Brand turbofish.
632	///
633	/// For most use cases, prefer the inference-enabled wrappers from
634	/// [`functions`](crate::functions).
635	pub mod explicit {
636		use super::*;
637
638		/// Sequences a monadic computation with a function that produces the next computation.
639		///
640		/// Dispatches to either [`Semimonad::bind`] or [`RefSemimonad::ref_bind`]
641		/// based on the closure's argument type.
642		///
643		/// The `Marker` and `FA` type parameters are inferred automatically by the
644		/// compiler from the closure's argument type and the container argument.
645		/// Callers write `bind::<Brand, _, _, _, _>(...)` and never need to specify
646		/// `Marker` or `FA` explicitly.
647		#[document_signature]
648		///
649		#[document_type_parameters(
650			"The lifetime of the values.",
651			"The brand of the monad.",
652			"The type of the value inside the monad.",
653			"The type of the result.",
654			"The container type (owned or borrowed), inferred from the argument.",
655			"Dispatch marker type, inferred automatically."
656		)]
657		///
658		#[document_parameters(
659			"The monadic value (owned for Val, borrowed for Ref).",
660			"The function to apply to the value."
661		)]
662		///
663		#[document_returns("The result of sequencing the computation.")]
664		#[document_examples]
665		///
666		/// ```
667		/// use fp_library::{
668		/// 	brands::*,
669		/// 	functions::explicit::*,
670		/// };
671		/// let result = bind::<OptionBrand, _, _, _, _>(Some(5), |x: i32| Some(x * 2));
672		/// assert_eq!(result, Some(10));
673		/// ```
674		pub fn bind<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, FA, Marker>(
675			ma: FA,
676			f: impl BindDispatch<'a, Brand, A, B, FA, Marker>,
677		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
678			f.dispatch(ma)
679		}
680
681		/// Binds a monadic value to a function (flipped argument order).
682		///
683		/// Dispatches to [`Semimonad::bind`] or [`RefSemimonad::ref_bind`]
684		/// based on whether the closure takes `A` or `&A`. Delegates to
685		/// [`BindDispatch`] internally.
686		#[document_signature]
687		///
688		#[document_type_parameters(
689			"The lifetime of the values.",
690			"The higher-kinded type brand.",
691			"The input element type.",
692			"The output element type.",
693			"The container type (owned or borrowed), inferred from the argument.",
694			"Marker type, inferred from the closure."
695		)]
696		///
697		#[document_parameters(
698			"The function to apply to each element.",
699			"The monadic value to bind over (owned for Val, borrowed for Ref)."
700		)]
701		///
702		#[document_returns("The result of binding the function over the value.")]
703		#[document_examples]
704		///
705		/// ```
706		/// use fp_library::{
707		/// 	brands::*,
708		/// 	functions::explicit::*,
709		/// };
710		///
711		/// // By-value
712		/// let result = bind_flipped::<OptionBrand, _, _, _, _>(|x: i32| Some(x * 2), Some(5));
713		/// assert_eq!(result, Some(10));
714		/// ```
715		pub fn bind_flipped<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, B: 'a, FA, Marker>(
716			f: impl BindDispatch<'a, Brand, A, B, FA, Marker>,
717			ma: FA,
718		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
719			f.dispatch(ma)
720		}
721
722		/// Removes one layer of monadic nesting.
723		///
724		/// Dispatches to either [`Semimonad::bind`] with identity or
725		/// [`RefSemimonad::ref_bind`] with clone, based on whether the
726		/// container is owned or borrowed.
727		///
728		/// The `Marker` type parameter is inferred automatically by the
729		/// compiler from the container argument. Callers write
730		/// `join::<Brand, _>(...)` and never need to specify `Marker` explicitly.
731		///
732		/// The dispatch is resolved at compile time with no runtime cost.
733		#[document_signature]
734		///
735		#[document_type_parameters(
736			"The lifetime of the values.",
737			"The brand of the monad.",
738			"The type of the value(s) inside the inner layer.",
739			"Dispatch marker type, inferred automatically."
740		)]
741		///
742		#[document_parameters("The nested monadic value (owned or borrowed).")]
743		///
744		#[document_returns("A container with one layer of nesting removed.")]
745		///
746		#[document_examples]
747		///
748		/// ```
749		/// use fp_library::{
750		/// 	brands::*,
751		/// 	functions::explicit::*,
752		/// };
753		///
754		/// // Owned: dispatches via Semimonad::bind(id)
755		/// let y = join::<OptionBrand, _, _>(Some(Some(5)));
756		/// assert_eq!(y, Some(5));
757		///
758		/// // By-ref: dispatches via RefSemimonad::ref_bind(clone)
759		/// let x = Some(Some(5));
760		/// let y = join::<OptionBrand, _, _>(&x);
761		/// assert_eq!(y, Some(5));
762		/// ```
763		pub fn join<'a, Brand: Kind_cdc7cd43dac7585f, A: 'a, Marker>(
764			mma: impl JoinDispatch<'a, Brand, A, Marker>
765		) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
766			mma.dispatch()
767		}
768	}
769}
770
771pub use inner::*;