Skip to main content

fp_library/
functions.rs

1//! The primary API for calling type class operations as free functions.
2//!
3//! Re-exports are drawn from three source modules, each serving a
4//! different role:
5//!
6//! - **[`dispatch`](crate::dispatch)** provides inference wrappers that
7//!   infer Brand (and sometimes FnBrand) from the container argument via
8//!   [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f).
9//!   These are the primary API for most operations (`map`, `bind`,
10//!   `fold_left`, `apply`, etc.). Val/Ref dispatch is also handled
11//!   automatically: passing an owned container dispatches to the Val
12//!   impl, passing a reference dispatches to the Ref impl.
13//!
14//! - **[`classes`](crate::classes)** provides free functions that take
15//!   Brand via turbofish. These cover operations where Brand cannot be
16//!   inferred from arguments because the container is constructed rather
17//!   than transformed (e.g., [`pure`], [`plus_empty`]), or where the
18//!   function was superseded by a dispatch wrapper and serves as the
19//!   explicit fallback.
20//!
21//! - **[`types`](crate::types)** provides type-specific utilities
22//!   (constructors, conversions) that do not go through the type class
23//!   system.
24//!
25//! The [`explicit`] submodule re-exports the explicit (turbofish-required)
26//! versions from each dispatch module, for cases where Brand inference is
27//! ambiguous (e.g., diagonal types like `Result<T, T>`, or generic
28//! contexts):
29//!
30//! ```
31//! use fp_library::functions::*;
32//!
33//! // Brand is inferred as VecBrand from the Vec argument.
34//! let result = map(|x: i32| x + 1, vec![1, 2, 3]);
35//! assert_eq!(result, vec![2, 3, 4]);
36//! ```
37//!
38//! ```
39//! use fp_library::{
40//! 	brands::*,
41//! 	functions::explicit::*,
42//! };
43//!
44//! // Brand specified explicitly via turbofish.
45//! let result = map::<VecBrand, _, _, _, _>(|x: i32| x + 1, vec![1, 2, 3]);
46//! assert_eq!(result, vec![2, 3, 4]);
47//! ```
48//!
49//! The module also defines standalone utility functions such as [`compose`],
50//! [`constant`], [`flip`], [`identity`], and [`on`].
51
52use fp_macros::*;
53
54pub use crate::{
55	// -- Class-level free functions (Brand via turbofish) --
56	//
57	// These are operations where Brand cannot be inferred from the
58	// arguments (e.g., constructors) or where no dispatch wrapper
59	// exists. Aliases avoid name collisions with other re-exports.
60	classes::{
61		alternative::guard,
62		applicative::{
63			unless,
64			when,
65		},
66		bitraversable::{
67			bi_for,
68			bi_sequence,
69			for_left,
70			for_right,
71			traverse_left,
72			traverse_right,
73		},
74		category::identity as category_identity,
75		clone_fn::new as lift_fn_new,
76		clone_fn::ref_new as ref_lift_fn_new,
77		deferrable::defer,
78		division_ring::{
79			divide_left,
80			divide_right,
81			reciprocate,
82		},
83		euclidean_ring::{
84			degree,
85			divide,
86			gcd,
87			lcm,
88			modulo,
89		},
90		extend::{
91			compose_co_kleisli,
92			compose_co_kleisli_flipped,
93			duplicate,
94			extend,
95			extend_flipped,
96		},
97		extract::extract,
98		heyting_algebra::{
99			conjoin,
100			disjoin,
101			false_value,
102			imply,
103			not,
104			true_value,
105		},
106		monad::{
107			if_m,
108			unless_m,
109			when_m,
110		},
111		monad_rec::{
112			forever,
113			repeat_m,
114			tail_rec_m,
115			until_m,
116			until_some,
117			while_m,
118			while_some,
119		},
120		monoid::{
121			empty,
122			power,
123		},
124		par_compactable::{
125			par_compact,
126			par_separate,
127		},
128		par_filterable::{
129			par_filter,
130			par_filter_map,
131		},
132		par_filterable_with_index::{
133			par_filter_map_with_index,
134			par_filter_with_index,
135		},
136		par_foldable::par_fold_map,
137		par_foldable_with_index::par_fold_map_with_index,
138		par_functor::par_map,
139		par_functor_with_index::par_map_with_index,
140		par_ref_filterable::{
141			par_ref_filter,
142			par_ref_filter_map,
143		},
144		par_ref_filterable_with_index::{
145			par_ref_filter_map_with_index,
146			par_ref_filter_with_index,
147		},
148		par_ref_foldable::par_ref_fold_map,
149		par_ref_foldable_with_index::par_ref_fold_map_with_index,
150		par_ref_functor::par_ref_map,
151		par_ref_functor_with_index::par_ref_map_with_index,
152		pipe::pipe,
153		plus::empty as plus_empty,
154		pointed::pure,
155		pointer::new as pointer_new,
156		profunctor::{
157			arrow,
158			dimap,
159			map_input,
160			map_output,
161		},
162		ref_bitraversable::{
163			ref_bi_for,
164			ref_bi_for_left,
165			ref_bi_for_right,
166			ref_bi_sequence,
167			ref_bi_traverse_left,
168			ref_bi_traverse_right,
169		},
170		ref_counted_pointer::new as ref_counted_pointer_new,
171		ref_counted_pointer::{
172			take_cell_new,
173			take_cell_take,
174			try_unwrap,
175		},
176		ref_monad::{
177			ref_if_m,
178			ref_unless_m,
179		},
180		ref_pointed::ref_pure,
181		ref_semiapplicative::ref_apply,
182		ref_traversable::ref_traverse,
183		ring::{
184			negate,
185			subtract,
186		},
187		semigroup::append,
188		semigroupoid::compose as semigroupoid_compose,
189		semiring::{
190			add,
191			multiply,
192			one,
193			zero,
194		},
195		send_clone_fn::new as send_lift_fn_new,
196		send_clone_fn::ref_new as send_ref_lift_fn_new,
197		send_deferrable::send_defer,
198		send_ref_apply_first::send_ref_apply_first,
199		send_ref_apply_second::send_ref_apply_second,
200		send_ref_counted_pointer::new as send_ref_counted_pointer_new,
201		send_ref_foldable::send_ref_fold_map,
202		send_ref_foldable_with_index::send_ref_fold_map_with_index,
203		send_ref_functor::send_ref_map,
204		send_ref_functor_with_index::send_ref_map_with_index,
205		send_ref_lift::send_ref_lift2,
206		send_ref_pointed::send_ref_pure,
207		send_ref_semiapplicative::send_ref_apply,
208		send_ref_semimonad::send_ref_bind,
209		to_dyn_clone_fn::new as to_dyn_clone_fn,
210		to_dyn_clone_fn::ref_new as to_ref_dyn_clone_fn,
211		to_dyn_fn::to_dyn_fn,
212		to_dyn_fn::to_ref_dyn_fn,
213		to_dyn_send_fn::new as to_dyn_send_fn,
214		to_dyn_send_fn::ref_new as to_ref_dyn_send_fn,
215		traversable::sequence,
216	},
217	// Inference wrappers (from dispatch modules, top-level of each).
218	dispatch::{
219		alt::alt,
220		apply_first::apply_first,
221		apply_second::apply_second,
222		bifoldable::{
223			bi_fold_left,
224			bi_fold_map,
225			bi_fold_right,
226		},
227		bifunctor::bimap,
228		bitraversable::bi_traverse,
229		compactable::{
230			compact,
231			separate,
232		},
233		contravariant::contramap,
234		filterable::{
235			filter,
236			filter_map,
237			partition,
238			partition_map,
239		},
240		filterable_with_index::{
241			filter_map_with_index,
242			filter_with_index,
243			partition_map_with_index,
244			partition_with_index,
245		},
246		foldable::{
247			fold_left,
248			fold_map,
249			fold_right,
250		},
251		foldable_with_index::{
252			fold_left_with_index,
253			fold_map_with_index,
254			fold_right_with_index,
255		},
256		functor::map,
257		functor_with_index::map_with_index,
258		lift::{
259			lift2,
260			lift3,
261			lift4,
262			lift5,
263		},
264		map_first::map_first,
265		map_second::map_second,
266		semiapplicative::apply,
267		semimonad::{
268			bind,
269			bind_flipped,
270			compose_kleisli,
271			compose_kleisli_flipped,
272			join,
273		},
274		traversable::traverse,
275		traversable_with_index::traverse_with_index,
276		witherable::{
277			wilt,
278			wither,
279		},
280	},
281	// -- Type-specific utilities --
282	types::{
283		lazy::{
284			arc_lazy_fix,
285			rc_lazy_fix,
286		},
287		optics::{
288			optics_as_index,
289			optics_compose,
290			optics_indexed_fold_map,
291			optics_indexed_over,
292			optics_indexed_preview,
293			optics_indexed_set,
294			optics_indexed_view,
295			optics_reindexed,
296			optics_un_index,
297			positions,
298		},
299	},
300};
301
302/// Explicit dispatch functions requiring a Brand turbofish.
303///
304/// For most use cases, prefer the inference-enabled wrappers from the parent
305/// [`functions`](crate::functions) module.
306pub mod explicit {
307	// The class-level apply serves as the explicit fallback (takes
308	// FnBrand and Brand via turbofish). The dispatch version infers both.
309	pub use crate::{
310		classes::semiapplicative::apply,
311		dispatch::{
312			alt::explicit::alt,
313			apply_first::explicit::apply_first,
314			apply_second::explicit::apply_second,
315			bifoldable::explicit::{
316				bi_fold_left,
317				bi_fold_map,
318				bi_fold_right,
319			},
320			bifunctor::explicit::bimap,
321			bitraversable::explicit::bi_traverse,
322			compactable::explicit::{
323				compact,
324				separate,
325			},
326			contravariant::explicit::contramap,
327			filterable::explicit::{
328				filter,
329				filter_map,
330				partition,
331				partition_map,
332			},
333			filterable_with_index::explicit::{
334				filter_map_with_index,
335				filter_with_index,
336				partition_map_with_index,
337				partition_with_index,
338			},
339			foldable::explicit::{
340				fold_left,
341				fold_map,
342				fold_right,
343			},
344			foldable_with_index::explicit::{
345				fold_left_with_index,
346				fold_map_with_index,
347				fold_right_with_index,
348			},
349			functor::explicit::map,
350			functor_with_index::explicit::map_with_index,
351			lift::explicit::{
352				lift2,
353				lift3,
354				lift4,
355				lift5,
356			},
357			map_first::explicit::map_first,
358			map_second::explicit::map_second,
359			semimonad::explicit::{
360				bind,
361				bind_flipped,
362				join,
363			},
364			traversable::explicit::traverse,
365			traversable_with_index::explicit::traverse_with_index,
366			witherable::explicit::{
367				wilt,
368				wither,
369			},
370		},
371	};
372}
373
374/// Composes two functions.
375///
376/// Takes two functions, `f` and `g`, and returns a new function that applies `g` to its argument,
377/// and then applies `f` to the result. This is equivalent to the mathematical composition `f ∘ g`.
378#[document_signature]
379///
380#[document_type_parameters(
381	"The input type of the inner function `g`.",
382	"The output type of `g` and the input type of `f`.",
383	"The output type of the outer function `f`."
384)]
385///
386#[document_parameters(
387	"The outer function to apply second.",
388	"The inner function to apply first.",
389	"The argument to be passed to the composed function."
390)]
391/// ### Returns
392///
393/// A new function that takes an `A` and returns a `C`.
394///
395/// ### Examples
396///
397/// ```rust
398/// use fp_library::functions::*;
399///
400/// let add_one = |x: i32| x + 1;
401/// let times_two = |x: i32| x * 2;
402/// let times_two_add_one = compose(add_one, times_two);
403///
404/// // 3 * 2 + 1 = 7
405/// assert_eq!(times_two_add_one(3), 7);
406/// ```
407pub fn compose<A, B, C>(
408	f: impl Fn(B) -> C,
409	g: impl Fn(A) -> B,
410) -> impl Fn(A) -> C {
411	move |a| f(g(a))
412}
413
414/// Creates a constant function.
415///
416/// Returns a function that ignores its argument and always returns the provided value `a`.
417/// This is useful when a function is expected but a constant value is needed.
418#[document_signature]
419///
420#[document_type_parameters(
421	"The type of the value to return.",
422	"The type of the argument to ignore."
423)]
424///
425#[document_parameters(
426	"The value to be returned by the constant function.",
427	"The argument to be ignored."
428)]
429/// ### Returns
430///
431/// The first parameter.
432///
433/// ### Examples
434///
435/// ```rust
436/// use fp_library::functions::*;
437///
438/// assert_eq!(constant(true, false), true);
439/// ```
440pub fn constant<A: Clone, B>(
441	a: A,
442	_b: B,
443) -> A {
444	a
445}
446
447/// Flips the arguments of a binary function.
448///
449/// Returns a new function that takes its arguments in the reverse order of the input function `f`.
450/// If `f` takes `(a, b)`, the returned function takes `(b, a)`.
451#[document_signature]
452///
453#[document_type_parameters(
454	"The type of the first argument of the input function.",
455	"The type of the second argument of the input function.",
456	"The return type of the function."
457)]
458///
459#[document_parameters(
460	"A binary function.",
461	"The second argument (which will be passed as the first to `f`).",
462	"The first argument (which will be passed as the second to `f`)."
463)]
464/// ### Returns
465///
466/// A version of `f` that takes its arguments in reverse.
467///
468/// ### Examples
469///
470/// ```rust
471/// use fp_library::functions::*;
472///
473/// let subtract = |a, b| a - b;
474///
475/// // 0 - 1 = -1
476/// assert_eq!(flip(subtract)(1, 0), -1);
477/// ```
478pub fn flip<A, B, C>(f: impl Fn(A, B) -> C) -> impl Fn(B, A) -> C {
479	move |b, a| f(a, b)
480}
481
482/// The identity function.
483///
484/// Returns its input argument as is. This is often used as a default or placeholder function.
485#[document_signature]
486///
487#[document_type_parameters("The type of the value.")]
488///
489#[document_parameters("A value.")]
490///
491/// ### Returns
492///
493/// The same value `a`.
494///
495/// ### Examples
496///
497/// ```rust
498/// use fp_library::functions::*;
499///
500/// assert_eq!(identity(()), ());
501/// ```
502pub fn identity<A>(a: A) -> A {
503	a
504}
505
506/// Applies a binary function after projecting both arguments through a common function.
507///
508/// `on(f, g, x, y)` computes `f(g(x), g(y))`. This is useful for changing the domain
509/// of a binary operation.
510#[document_signature]
511///
512#[document_type_parameters(
513	"The type of the original arguments.",
514	"The type of the projected arguments.",
515	"The result type."
516)]
517///
518#[document_parameters(
519	"The binary function to apply to the projected values.",
520	"The projection function applied to both arguments.",
521	"The first argument.",
522	"The second argument."
523)]
524///
525#[document_returns("The result of applying `f` to the projected values.")]
526#[document_examples]
527///
528/// ```
529/// use fp_library::functions::*;
530///
531/// // Compare by absolute value
532/// let max_by_abs = on(|a: i32, b: i32| a.max(b), |x: i32| x.abs(), -5, 3);
533/// assert_eq!(max_by_abs, 5);
534///
535/// // Sum the lengths of two strings
536/// let sum_lens = on(|a: usize, b: usize| a + b, |s: &str| s.len(), "hello", "hi");
537/// assert_eq!(sum_lens, 7);
538/// ```
539pub fn on<A, B, C>(
540	f: impl Fn(B, B) -> C,
541	g: impl Fn(A) -> B,
542	x: A,
543	y: A,
544) -> C {
545	f(g(x), g(y))
546}