Skip to main content

fp_library/dispatch/
bifoldable.rs

1//! Dispatch for bifoldable operations:
2//! [`Bifoldable`](crate::classes::Bifoldable) and
3//! [`RefBifoldable`](crate::classes::RefBifoldable).
4//!
5//! Provides the following dispatch traits and unified free functions:
6//!
7//! - [`BiFoldLeftDispatch`] + [`explicit::bi_fold_left`]
8//! - [`BiFoldRightDispatch`] + [`explicit::bi_fold_right`]
9//! - [`BiFoldMapDispatch`] + [`explicit::bi_fold_map`]
10//!
11//! Each routes to the appropriate trait method based on the closures' argument
12//! types.
13//!
14//! ### Examples
15//!
16//! ```
17//! use fp_library::{
18//! 	brands::*,
19//! 	functions::explicit::*,
20//! };
21//!
22//! // bi_fold_left
23//! let x: Result<i32, i32> = Ok(5);
24//! let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
25//! 	(|acc, e| acc - e, |acc, s| acc + s),
26//! 	10,
27//! 	x,
28//! );
29//! assert_eq!(y, 15);
30//!
31//! // bi_fold_right
32//! let x: Result<i32, i32> = Err(3);
33//! let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
34//! 	(|e, acc| acc - e, |s, acc| acc + s),
35//! 	10,
36//! 	x,
37//! );
38//! assert_eq!(y, 7);
39//!
40//! // bi_fold_map
41//! let x: Result<i32, i32> = Ok(5);
42//! let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
43//! 	(|e: i32| e.to_string(), |s: i32| s.to_string()),
44//! 	x,
45//! );
46//! assert_eq!(y, "5".to_string());
47//! ```
48
49#[fp_macros::document_module]
50pub(crate) mod inner {
51	use {
52		crate::{
53			classes::{
54				Bifoldable,
55				LiftFn,
56				Monoid,
57				RefBifoldable,
58			},
59			dispatch::{
60				Ref,
61				Val,
62			},
63			kinds::*,
64		},
65		fp_macros::*,
66	};
67
68	// -- BiFoldLeftDispatch --
69
70	/// Trait that routes a bi_fold_left operation to the appropriate type class method.
71	///
72	/// `(Fn(C, A) -> C, Fn(C, B) -> C)` resolves to [`Val`],
73	/// `(Fn(C, &A) -> C, Fn(C, &B) -> C)` resolves to [`Ref`].
74	#[document_type_parameters(
75		"The lifetime of the values.",
76		"The brand of the cloneable function to use.",
77		"The brand of the bifoldable structure.",
78		"The type of the first-position elements.",
79		"The type of the second-position elements.",
80		"The type of the accumulator.",
81		"The container type (owned or borrowed), inferred from the argument.",
82		"Dispatch marker type, inferred automatically."
83	)]
84	#[document_parameters("The closure tuple implementing this dispatch.")]
85	pub trait BiFoldLeftDispatch<
86		'a,
87		FnBrand,
88		Brand: Kind_266801a817966495,
89		A: 'a,
90		B: 'a,
91		C: 'a,
92		FA,
93		Marker,
94	> {
95		/// Perform the dispatched bi_fold_left operation.
96		#[document_signature]
97		#[document_parameters("The initial accumulator value.", "The structure to fold.")]
98		#[document_returns("The final accumulator value.")]
99		#[document_examples]
100		///
101		/// ```
102		/// use fp_library::{
103		/// 	brands::*,
104		/// 	functions::explicit::*,
105		/// };
106		/// let x: Result<i32, i32> = Ok(5);
107		/// let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
108		/// 	(|acc, e| acc - e, |acc, s| acc + s),
109		/// 	10,
110		/// 	x,
111		/// );
112		/// assert_eq!(y, 15);
113		/// ```
114		fn dispatch(
115			self,
116			z: C,
117			fa: FA,
118		) -> C;
119	}
120
121	/// Routes `(Fn(C, A) -> C, Fn(C, B) -> C)` closure tuples to [`Bifoldable::bi_fold_left`].
122	#[document_type_parameters(
123		"The lifetime.",
124		"The cloneable function brand.",
125		"The bifoldable brand.",
126		"The first element type.",
127		"The second element type.",
128		"The accumulator type.",
129		"The first closure type.",
130		"The second closure type."
131	)]
132	#[document_parameters("The closure tuple.")]
133	impl<'a, FnBrand, Brand, A, B, C, F, G>
134		BiFoldLeftDispatch<
135			'a,
136			FnBrand,
137			Brand,
138			A,
139			B,
140			C,
141			Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
142			Val,
143		> for (F, G)
144	where
145		Brand: Bifoldable,
146		FnBrand: LiftFn + 'a,
147		A: 'a + Clone,
148		B: 'a + Clone,
149		C: 'a,
150		F: Fn(C, A) -> C + 'a,
151		G: Fn(C, B) -> C + 'a,
152	{
153		#[document_signature]
154		#[document_parameters("The initial accumulator value.", "The structure to fold.")]
155		#[document_returns("The final accumulator value.")]
156		#[document_examples]
157		///
158		/// ```
159		/// use fp_library::{
160		/// 	brands::*,
161		/// 	functions::explicit::*,
162		/// };
163		/// let x: Result<i32, i32> = Ok(5);
164		/// let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
165		/// 	(|acc, e| acc - e, |acc, s| acc + s),
166		/// 	10,
167		/// 	x,
168		/// );
169		/// assert_eq!(y, 15);
170		/// ```
171		fn dispatch(
172			self,
173			z: C,
174			fa: Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
175		) -> C {
176			Brand::bi_fold_left::<FnBrand, A, B, C>(self.0, self.1, z, fa)
177		}
178	}
179
180	/// Routes `(Fn(C, &A) -> C, Fn(C, &B) -> C)` closure tuples to [`RefBifoldable::ref_bi_fold_left`].
181	///
182	/// The container must be passed by reference (`&p`).
183	#[document_type_parameters(
184		"The lifetime.",
185		"The borrow lifetime.",
186		"The cloneable function brand.",
187		"The bifoldable brand.",
188		"The first element type.",
189		"The second element type.",
190		"The accumulator type.",
191		"The first closure type.",
192		"The second closure type."
193	)]
194	#[document_parameters("The closure tuple.")]
195	impl<'a, 'b, FnBrand, Brand, A, B, C, F, G>
196		BiFoldLeftDispatch<
197			'a,
198			FnBrand,
199			Brand,
200			A,
201			B,
202			C,
203			&'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
204			Ref,
205		> for (F, G)
206	where
207		Brand: RefBifoldable,
208		FnBrand: LiftFn + 'a,
209		A: 'a + Clone,
210		B: 'a + Clone,
211		C: 'a,
212		F: Fn(C, &A) -> C + 'a,
213		G: Fn(C, &B) -> C + 'a,
214	{
215		#[document_signature]
216		#[document_parameters(
217			"The initial accumulator value.",
218			"A reference to the structure to fold."
219		)]
220		#[document_returns("The final accumulator value.")]
221		#[document_examples]
222		///
223		/// ```
224		/// use fp_library::{
225		/// 	brands::*,
226		/// 	functions::explicit::*,
227		/// };
228		/// let x: Result<i32, i32> = Ok(5);
229		/// let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
230		/// 	(|acc, e: &i32| acc - *e, |acc, s: &i32| acc + *s),
231		/// 	10,
232		/// 	&x,
233		/// );
234		/// assert_eq!(y, 15);
235		/// ```
236		fn dispatch(
237			self,
238			z: C,
239			fa: &'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
240		) -> C {
241			Brand::ref_bi_fold_left::<FnBrand, A, B, C>(self.0, self.1, z, fa)
242		}
243	}
244
245	// -- BiFoldRightDispatch --
246
247	/// Trait that routes a bi_fold_right operation to the appropriate type class method.
248	///
249	/// `(Fn(A, C) -> C, Fn(B, C) -> C)` resolves to [`Val`],
250	/// `(Fn(&A, C) -> C, Fn(&B, C) -> C)` resolves to [`Ref`].
251	#[document_type_parameters(
252		"The lifetime of the values.",
253		"The brand of the cloneable function to use.",
254		"The brand of the bifoldable structure.",
255		"The type of the first-position elements.",
256		"The type of the second-position elements.",
257		"The type of the accumulator.",
258		"The container type (owned or borrowed), inferred from the argument.",
259		"Dispatch marker type, inferred automatically."
260	)]
261	#[document_parameters("The closure tuple implementing this dispatch.")]
262	pub trait BiFoldRightDispatch<
263		'a,
264		FnBrand,
265		Brand: Kind_266801a817966495,
266		A: 'a,
267		B: 'a,
268		C: 'a,
269		FA,
270		Marker,
271	> {
272		/// Perform the dispatched bi_fold_right operation.
273		#[document_signature]
274		#[document_parameters("The initial accumulator value.", "The structure to fold.")]
275		#[document_returns("The final accumulator value.")]
276		#[document_examples]
277		///
278		/// ```
279		/// use fp_library::{
280		/// 	brands::*,
281		/// 	functions::explicit::*,
282		/// };
283		/// let x: Result<i32, i32> = Err(3);
284		/// let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
285		/// 	(|e, acc| acc - e, |s, acc| acc + s),
286		/// 	10,
287		/// 	x,
288		/// );
289		/// assert_eq!(y, 7);
290		/// ```
291		fn dispatch(
292			self,
293			z: C,
294			fa: FA,
295		) -> C;
296	}
297
298	/// Routes `(Fn(A, C) -> C, Fn(B, C) -> C)` closure tuples to [`Bifoldable::bi_fold_right`].
299	#[document_type_parameters(
300		"The lifetime.",
301		"The cloneable function brand.",
302		"The bifoldable brand.",
303		"The first element type.",
304		"The second element type.",
305		"The accumulator type.",
306		"The first closure type.",
307		"The second closure type."
308	)]
309	#[document_parameters("The closure tuple.")]
310	impl<'a, FnBrand, Brand, A, B, C, F, G>
311		BiFoldRightDispatch<
312			'a,
313			FnBrand,
314			Brand,
315			A,
316			B,
317			C,
318			Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
319			Val,
320		> for (F, G)
321	where
322		Brand: Bifoldable,
323		FnBrand: LiftFn + 'a,
324		A: 'a + Clone,
325		B: 'a + Clone,
326		C: 'a,
327		F: Fn(A, C) -> C + 'a,
328		G: Fn(B, C) -> C + 'a,
329	{
330		#[document_signature]
331		#[document_parameters("The initial accumulator value.", "The structure to fold.")]
332		#[document_returns("The final accumulator value.")]
333		#[document_examples]
334		///
335		/// ```
336		/// use fp_library::{
337		/// 	brands::*,
338		/// 	functions::explicit::*,
339		/// };
340		/// let x: Result<i32, i32> = Err(3);
341		/// let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
342		/// 	(|e, acc| acc - e, |s, acc| acc + s),
343		/// 	10,
344		/// 	x,
345		/// );
346		/// assert_eq!(y, 7);
347		/// ```
348		fn dispatch(
349			self,
350			z: C,
351			fa: Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
352		) -> C {
353			Brand::bi_fold_right::<FnBrand, A, B, C>(self.0, self.1, z, fa)
354		}
355	}
356
357	/// Routes `(Fn(&A, C) -> C, Fn(&B, C) -> C)` closure tuples to [`RefBifoldable::ref_bi_fold_right`].
358	///
359	/// The container must be passed by reference (`&p`).
360	#[document_type_parameters(
361		"The lifetime.",
362		"The borrow lifetime.",
363		"The cloneable function brand.",
364		"The bifoldable brand.",
365		"The first element type.",
366		"The second element type.",
367		"The accumulator type.",
368		"The first closure type.",
369		"The second closure type."
370	)]
371	#[document_parameters("The closure tuple.")]
372	impl<'a, 'b, FnBrand, Brand, A, B, C, F, G>
373		BiFoldRightDispatch<
374			'a,
375			FnBrand,
376			Brand,
377			A,
378			B,
379			C,
380			&'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
381			Ref,
382		> for (F, G)
383	where
384		Brand: RefBifoldable,
385		FnBrand: LiftFn + 'a,
386		A: 'a + Clone,
387		B: 'a + Clone,
388		C: 'a,
389		F: Fn(&A, C) -> C + 'a,
390		G: Fn(&B, C) -> C + 'a,
391	{
392		#[document_signature]
393		#[document_parameters(
394			"The initial accumulator value.",
395			"A reference to the structure to fold."
396		)]
397		#[document_returns("The final accumulator value.")]
398		#[document_examples]
399		///
400		/// ```
401		/// use fp_library::{
402		/// 	brands::*,
403		/// 	functions::explicit::*,
404		/// };
405		/// let x: Result<i32, i32> = Err(3);
406		/// let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
407		/// 	(|e: &i32, acc| acc - *e, |s: &i32, acc| acc + *s),
408		/// 	10,
409		/// 	&x,
410		/// );
411		/// assert_eq!(y, 7);
412		/// ```
413		fn dispatch(
414			self,
415			z: C,
416			fa: &'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
417		) -> C {
418			Brand::ref_bi_fold_right::<FnBrand, A, B, C>(self.0, self.1, z, fa)
419		}
420	}
421
422	// -- BiFoldMapDispatch --
423
424	/// Trait that routes a bi_fold_map operation to the appropriate type class method.
425	///
426	/// `(Fn(A) -> M, Fn(B) -> M)` resolves to [`Val`],
427	/// `(Fn(&A) -> M, Fn(&B) -> M)` resolves to [`Ref`].
428	#[document_type_parameters(
429		"The lifetime of the values.",
430		"The brand of the cloneable function to use.",
431		"The brand of the bifoldable structure.",
432		"The type of the first-position elements.",
433		"The type of the second-position elements.",
434		"The monoid type.",
435		"The container type (owned or borrowed), inferred from the argument.",
436		"Dispatch marker type, inferred automatically."
437	)]
438	#[document_parameters("The closure tuple implementing this dispatch.")]
439	pub trait BiFoldMapDispatch<
440		'a,
441		FnBrand,
442		Brand: Kind_266801a817966495,
443		A: 'a,
444		B: 'a,
445		M,
446		FA,
447		Marker,
448	> {
449		/// Perform the dispatched bi_fold_map operation.
450		#[document_signature]
451		#[document_parameters("The structure to fold.")]
452		#[document_returns("The combined monoid value.")]
453		#[document_examples]
454		///
455		/// ```
456		/// use fp_library::{
457		/// 	brands::*,
458		/// 	functions::explicit::*,
459		/// };
460		/// let x: Result<i32, i32> = Ok(5);
461		/// let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
462		/// 	(|e: i32| e.to_string(), |s: i32| s.to_string()),
463		/// 	x,
464		/// );
465		/// assert_eq!(y, "5".to_string());
466		/// ```
467		fn dispatch(
468			self,
469			fa: FA,
470		) -> M;
471	}
472
473	/// Routes `(Fn(A) -> M, Fn(B) -> M)` closure tuples to [`Bifoldable::bi_fold_map`].
474	#[document_type_parameters(
475		"The lifetime.",
476		"The cloneable function brand.",
477		"The bifoldable brand.",
478		"The first element type.",
479		"The second element type.",
480		"The monoid type.",
481		"The first closure type.",
482		"The second closure type."
483	)]
484	#[document_parameters("The closure tuple.")]
485	impl<'a, FnBrand, Brand, A, B, M, F, G>
486		BiFoldMapDispatch<
487			'a,
488			FnBrand,
489			Brand,
490			A,
491			B,
492			M,
493			Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
494			Val,
495		> for (F, G)
496	where
497		Brand: Bifoldable,
498		FnBrand: LiftFn + 'a,
499		A: 'a + Clone,
500		B: 'a + Clone,
501		M: Monoid + 'a,
502		F: Fn(A) -> M + 'a,
503		G: Fn(B) -> M + 'a,
504	{
505		#[document_signature]
506		#[document_parameters("The structure to fold.")]
507		#[document_returns("The combined monoid value.")]
508		#[document_examples]
509		///
510		/// ```
511		/// use fp_library::{
512		/// 	brands::*,
513		/// 	functions::explicit::*,
514		/// };
515		/// let x: Result<i32, i32> = Ok(5);
516		/// let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
517		/// 	(|e: i32| e.to_string(), |s: i32| s.to_string()),
518		/// 	x,
519		/// );
520		/// assert_eq!(y, "5".to_string());
521		/// ```
522		fn dispatch(
523			self,
524			fa: Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
525		) -> M {
526			Brand::bi_fold_map::<FnBrand, A, B, M>(self.0, self.1, fa)
527		}
528	}
529
530	/// Routes `(Fn(&A) -> M, Fn(&B) -> M)` closure tuples to [`RefBifoldable::ref_bi_fold_map`].
531	///
532	/// The container must be passed by reference (`&p`).
533	#[document_type_parameters(
534		"The lifetime.",
535		"The borrow lifetime.",
536		"The cloneable function brand.",
537		"The bifoldable brand.",
538		"The first element type.",
539		"The second element type.",
540		"The monoid type.",
541		"The first closure type.",
542		"The second closure type."
543	)]
544	#[document_parameters("The closure tuple.")]
545	impl<'a, 'b, FnBrand, Brand, A, B, M, F, G>
546		BiFoldMapDispatch<
547			'a,
548			FnBrand,
549			Brand,
550			A,
551			B,
552			M,
553			&'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
554			Ref,
555		> for (F, G)
556	where
557		Brand: RefBifoldable,
558		FnBrand: LiftFn + 'a,
559		A: Clone + 'a,
560		B: Clone + 'a,
561		M: Monoid + 'a,
562		F: Fn(&A) -> M + 'a,
563		G: Fn(&B) -> M + 'a,
564	{
565		#[document_signature]
566		#[document_parameters("A reference to the structure to fold.")]
567		#[document_returns("The combined monoid value.")]
568		#[document_examples]
569		///
570		/// ```
571		/// use fp_library::{
572		/// 	brands::*,
573		/// 	functions::explicit::*,
574		/// };
575		/// let x: Result<i32, i32> = Ok(5);
576		/// let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
577		/// 	(|e: &i32| e.to_string(), |s: &i32| s.to_string()),
578		/// 	&x,
579		/// );
580		/// assert_eq!(y, "5".to_string());
581		/// ```
582		fn dispatch(
583			self,
584			fa: &'b Apply!(<Brand as Kind!( type Of<'a, A: 'a, B: 'a>: 'a; )>::Of<'a, A, B>),
585		) -> M {
586			Brand::ref_bi_fold_map::<FnBrand, A, B, M>(self.0, self.1, fa)
587		}
588	}
589
590	// -- Inference wrappers --
591
592	/// Left-folds over a bifoldable structure, inferring the brand from the
593	/// container type.
594	///
595	/// The `Brand` type parameter is inferred from the concrete type of `fa` via
596	/// the `InferableBrand` trait. `FnBrand` must still be specified explicitly.
597	///
598	/// For types that need an explicit brand, use
599	/// [`explicit::bi_fold_left`](crate::functions::explicit::bi_fold_left).
600	#[document_signature]
601	///
602	#[document_type_parameters(
603		"The lifetime of the values.",
604		"The cloneable function brand.",
605		"The container type (owned or borrowed). Brand is inferred from this.",
606		"The type of the first element.",
607		"The type of the second element.",
608		"The accumulator type.",
609		"The brand, inferred via InferableBrand from FA and the closure's input type."
610	)]
611	///
612	#[document_parameters(
613		"A tuple of (first fold function, second fold function).",
614		"The initial accumulator value.",
615		"The bifoldable value (owned for Val, borrowed for Ref)."
616	)]
617	///
618	#[document_returns("The final accumulator value.")]
619	#[document_examples]
620	///
621	/// ```
622	/// use fp_library::{
623	/// 	brands::*,
624	/// 	functions::*,
625	/// };
626	///
627	/// let x: Result<i32, i32> = Ok(5);
628	/// let y = bi_fold_left::<RcFnBrand, _, _, _, _, _>((|acc, e| acc - e, |acc, s| acc + s), 10, x);
629	/// assert_eq!(y, 15);
630	/// ```
631	pub fn bi_fold_left<'a, FnBrand, FA, A: 'a, B: 'a, C: 'a, Brand>(
632		fg: impl BiFoldLeftDispatch<
633			'a,
634			FnBrand,
635			Brand,
636			A,
637			B,
638			C,
639			FA,
640			<FA as InferableBrand_266801a817966495<'a, Brand, A, B>>::Marker,
641		>,
642		z: C,
643		fa: FA,
644	) -> C
645	where
646		Brand: Kind_266801a817966495,
647		FA: InferableBrand_266801a817966495<'a, Brand, A, B>, {
648		fg.dispatch(z, fa)
649	}
650
651	/// Right-folds over a bifoldable structure, inferring the brand from the
652	/// container type.
653	///
654	/// The `Brand` type parameter is inferred from the concrete type of `fa` via
655	/// the `InferableBrand` trait. `FnBrand` must still be specified explicitly.
656	///
657	/// For types that need an explicit brand, use
658	/// [`explicit::bi_fold_right`](crate::functions::explicit::bi_fold_right).
659	#[document_signature]
660	///
661	#[document_type_parameters(
662		"The lifetime of the values.",
663		"The cloneable function brand.",
664		"The container type (owned or borrowed). Brand is inferred from this.",
665		"The type of the first element.",
666		"The type of the second element.",
667		"The accumulator type.",
668		"The brand, inferred via InferableBrand from FA and the closure's input type."
669	)]
670	///
671	#[document_parameters(
672		"A tuple of (first fold function, second fold function).",
673		"The initial accumulator value.",
674		"The bifoldable value (owned for Val, borrowed for Ref)."
675	)]
676	///
677	#[document_returns("The final accumulator value.")]
678	#[document_examples]
679	///
680	/// ```
681	/// use fp_library::{
682	/// 	brands::*,
683	/// 	functions::*,
684	/// };
685	///
686	/// let x: Result<i32, i32> = Err(3);
687	/// let y = bi_fold_right::<RcFnBrand, _, _, _, _, _>((|e, acc| acc - e, |s, acc| acc + s), 10, x);
688	/// assert_eq!(y, 7);
689	/// ```
690	pub fn bi_fold_right<'a, FnBrand, FA, A: 'a, B: 'a, C: 'a, Brand>(
691		fg: impl BiFoldRightDispatch<
692			'a,
693			FnBrand,
694			Brand,
695			A,
696			B,
697			C,
698			FA,
699			<FA as InferableBrand_266801a817966495<'a, Brand, A, B>>::Marker,
700		>,
701		z: C,
702		fa: FA,
703	) -> C
704	where
705		Brand: Kind_266801a817966495,
706		FA: InferableBrand_266801a817966495<'a, Brand, A, B>, {
707		fg.dispatch(z, fa)
708	}
709
710	/// Folds a bifoldable structure into a monoid, inferring the brand from the
711	/// container type.
712	///
713	/// The `Brand` type parameter is inferred from the concrete type of `fa` via
714	/// the `InferableBrand` trait. `FnBrand` must still be specified explicitly.
715	///
716	/// For types that need an explicit brand, use
717	/// [`explicit::bi_fold_map`](crate::functions::explicit::bi_fold_map).
718	#[document_signature]
719	///
720	#[document_type_parameters(
721		"The lifetime of the values.",
722		"The cloneable function brand.",
723		"The container type (owned or borrowed). Brand is inferred from this.",
724		"The type of the first element.",
725		"The type of the second element.",
726		"The monoid type to fold into.",
727		"The brand, inferred via InferableBrand from FA and the closure's input type."
728	)]
729	///
730	#[document_parameters(
731		"A tuple of (first mapping function, second mapping function).",
732		"The bifoldable value (owned for Val, borrowed for Ref)."
733	)]
734	///
735	#[document_returns("The monoidal result of folding.")]
736	#[document_examples]
737	///
738	/// ```
739	/// use fp_library::{
740	/// 	brands::*,
741	/// 	functions::*,
742	/// };
743	///
744	/// let x: Result<i32, i32> = Ok(5);
745	/// let y = bi_fold_map::<RcFnBrand, _, _, _, _, _>(
746	/// 	(|e: &i32| e.to_string(), |s: &i32| s.to_string()),
747	/// 	&x,
748	/// );
749	/// assert_eq!(y, "5".to_string());
750	/// ```
751	pub fn bi_fold_map<'a, FnBrand, FA, A: 'a, B: 'a, M: Monoid + 'a, Brand>(
752		fg: impl BiFoldMapDispatch<
753			'a,
754			FnBrand,
755			Brand,
756			A,
757			B,
758			M,
759			FA,
760			<FA as InferableBrand_266801a817966495<'a, Brand, A, B>>::Marker,
761		>,
762		fa: FA,
763	) -> M
764	where
765		Brand: Kind_266801a817966495,
766		FA: InferableBrand_266801a817966495<'a, Brand, A, B>, {
767		fg.dispatch(fa)
768	}
769
770	// -- Explicit dispatch free functions --
771
772	/// Explicit dispatch functions requiring a Brand turbofish.
773	///
774	/// For most use cases, prefer the inference-enabled wrappers from
775	/// [`functions`](crate::functions).
776	pub mod explicit {
777		use super::*;
778
779		/// Folds a bifoldable structure from the left.
780		///
781		/// Dispatches to [`Bifoldable::bi_fold_left`] or [`RefBifoldable::ref_bi_fold_left`]
782		/// based on whether the closures take owned or reference arguments.
783		#[document_signature]
784		#[document_type_parameters(
785			"The lifetime of the values.",
786			"The brand of the cloneable function to use.",
787			"The brand of the bifoldable structure.",
788			"The type of the first-position elements.",
789			"The type of the second-position elements.",
790			"The type of the accumulator.",
791			"The container type (owned or borrowed), inferred from the argument.",
792			"Dispatch marker type, inferred automatically."
793		)]
794		#[document_parameters(
795			"A tuple of (first step function, second step function).",
796			"The initial accumulator value.",
797			"The structure to fold (owned for Val, borrowed for Ref)."
798		)]
799		#[document_returns("The final accumulator value.")]
800		#[document_examples]
801		///
802		/// ```
803		/// use fp_library::{
804		/// 	brands::*,
805		/// 	functions::explicit::*,
806		/// };
807		///
808		/// let x: Result<i32, i32> = Ok(5);
809		/// let y = bi_fold_left::<RcFnBrand, ResultBrand, _, _, _, _, _>(
810		/// 	(|acc, e| acc - e, |acc, s| acc + s),
811		/// 	10,
812		/// 	x,
813		/// );
814		/// assert_eq!(y, 15);
815		/// ```
816		pub fn bi_fold_left<
817			'a,
818			FnBrand,
819			Brand: Kind_266801a817966495,
820			A: 'a,
821			B: 'a,
822			C: 'a,
823			FA,
824			Marker,
825		>(
826			fg: impl BiFoldLeftDispatch<'a, FnBrand, Brand, A, B, C, FA, Marker>,
827			z: C,
828			fa: FA,
829		) -> C {
830			fg.dispatch(z, fa)
831		}
832
833		/// Folds a bifoldable structure from the right.
834		///
835		/// Dispatches to [`Bifoldable::bi_fold_right`] or [`RefBifoldable::ref_bi_fold_right`]
836		/// based on whether the closures take owned or reference arguments.
837		#[document_signature]
838		#[document_type_parameters(
839			"The lifetime of the values.",
840			"The brand of the cloneable function to use.",
841			"The brand of the bifoldable structure.",
842			"The type of the first-position elements.",
843			"The type of the second-position elements.",
844			"The type of the accumulator.",
845			"The container type (owned or borrowed), inferred from the argument.",
846			"Dispatch marker type, inferred automatically."
847		)]
848		#[document_parameters(
849			"A tuple of (first step function, second step function).",
850			"The initial accumulator value.",
851			"The structure to fold (owned for Val, borrowed for Ref)."
852		)]
853		#[document_returns("The final accumulator value.")]
854		#[document_examples]
855		///
856		/// ```
857		/// use fp_library::{
858		/// 	brands::*,
859		/// 	functions::explicit::*,
860		/// };
861		///
862		/// let x: Result<i32, i32> = Err(3);
863		/// let y = bi_fold_right::<RcFnBrand, ResultBrand, _, _, _, _, _>(
864		/// 	(|e, acc| acc - e, |s, acc| acc + s),
865		/// 	10,
866		/// 	x,
867		/// );
868		/// assert_eq!(y, 7);
869		/// ```
870		pub fn bi_fold_right<
871			'a,
872			FnBrand,
873			Brand: Kind_266801a817966495,
874			A: 'a,
875			B: 'a,
876			C: 'a,
877			FA,
878			Marker,
879		>(
880			fg: impl BiFoldRightDispatch<'a, FnBrand, Brand, A, B, C, FA, Marker>,
881			z: C,
882			fa: FA,
883		) -> C {
884			fg.dispatch(z, fa)
885		}
886
887		/// Maps elements of both types to a monoid and combines them.
888		///
889		/// Dispatches to [`Bifoldable::bi_fold_map`] or [`RefBifoldable::ref_bi_fold_map`]
890		/// based on whether the closures take owned or reference arguments.
891		#[document_signature]
892		#[document_type_parameters(
893			"The lifetime of the values.",
894			"The brand of the cloneable function to use.",
895			"The brand of the bifoldable structure.",
896			"The type of the first-position elements.",
897			"The type of the second-position elements.",
898			"The monoid type.",
899			"The container type (owned or borrowed), inferred from the argument.",
900			"Dispatch marker type, inferred automatically."
901		)]
902		#[document_parameters(
903			"A tuple of (first mapping function, second mapping function).",
904			"The structure to fold (owned for Val, borrowed for Ref)."
905		)]
906		#[document_returns("The combined monoid value.")]
907		#[document_examples]
908		///
909		/// ```
910		/// use fp_library::{
911		/// 	brands::*,
912		/// 	functions::explicit::*,
913		/// };
914		///
915		/// let x: Result<i32, i32> = Ok(5);
916		/// let y = bi_fold_map::<RcFnBrand, ResultBrand, _, _, _, _, _>(
917		/// 	(|e: i32| e.to_string(), |s: i32| s.to_string()),
918		/// 	x,
919		/// );
920		/// assert_eq!(y, "5".to_string());
921		/// ```
922		pub fn bi_fold_map<
923			'a,
924			FnBrand,
925			Brand: Kind_266801a817966495,
926			A: 'a,
927			B: 'a,
928			M: Monoid + 'a,
929			FA,
930			Marker,
931		>(
932			fg: impl BiFoldMapDispatch<'a, FnBrand, Brand, A, B, M, FA, Marker>,
933			fa: FA,
934		) -> M {
935			fg.dispatch(fa)
936		}
937	}
938}
939
940pub use inner::*;