Skip to main content

fp_library/
functions.rs

1//! The primary API for calling type class operations as free functions.
2//!
3//! This module re-exports inference-enabled dispatch functions from
4//! [`dispatch`](crate::dispatch). These functions automatically infer the
5//! Brand type parameter from the container argument, so callers do not need
6//! a turbofish annotation:
7//!
8//! ```
9//! use fp_library::functions::*;
10//!
11//! // Brand is inferred as VecBrand from the Vec argument.
12//! let result = map(|x: i32| x + 1, vec![1, 2, 3]);
13//! assert_eq!(result, vec![2, 3, 4]);
14//! ```
15//!
16//! For cases where Brand inference is ambiguous (e.g., generic contexts),
17//! the [`explicit`] submodule provides versions that require a Brand
18//! turbofish:
19//!
20//! ```
21//! use fp_library::{
22//! 	brands::*,
23//! 	functions::explicit::*,
24//! };
25//!
26//! let result = map::<VecBrand, _, _, _, _>(|x: i32| x + 1, vec![1, 2, 3]);
27//! assert_eq!(result, vec![2, 3, 4]);
28//! ```
29//!
30//! The module also defines standalone utility functions such as [`compose`],
31//! [`constant`], [`flip`], [`identity`], and [`on`].
32
33use fp_macros::*;
34
35pub use crate::dispatch::contravariant::contramap;
36// Inference wrappers (from dispatch modules, top-level of each).
37pub use crate::dispatch::{
38	alt::alt,
39	apply_first::apply_first,
40	apply_second::apply_second,
41	bifoldable::{
42		bi_fold_left,
43		bi_fold_map,
44		bi_fold_right,
45	},
46	bifunctor::bimap,
47	bitraversable::bi_traverse,
48	compactable::{
49		compact,
50		separate,
51	},
52	filterable::{
53		filter,
54		filter_map,
55		partition,
56		partition_map,
57	},
58	filterable_with_index::{
59		filter_map_with_index,
60		filter_with_index,
61		partition_map_with_index,
62		partition_with_index,
63	},
64	foldable::{
65		fold_left,
66		fold_map,
67		fold_right,
68	},
69	foldable_with_index::{
70		fold_left_with_index,
71		fold_map_with_index,
72		fold_right_with_index,
73	},
74	functor::map,
75	functor_with_index::map_with_index,
76	lift::{
77		lift2,
78		lift3,
79		lift4,
80		lift5,
81	},
82	semimonad::{
83		bind,
84		bind_flipped,
85		join,
86	},
87	traversable::traverse,
88	traversable_with_index::traverse_with_index,
89	witherable::{
90		wilt,
91		wither,
92	},
93};
94// Auto-generate re-exports, passing in aliases for conflicting names.
95fp_macros::generate_function_re_exports!("src/classes", {
96	"category::identity": category_identity,
97	"clone_fn::new": lift_fn_new,
98	"clone_fn::ref_new": ref_lift_fn_new,
99	"pointer::new": pointer_new,
100	"ref_counted_pointer::cloneable_new": ref_counted_pointer_new,
101	"send_ref_counted_pointer::send_new": send_ref_counted_pointer_new,
102	"plus::empty": plus_empty,
103	"semigroupoid::compose": semigroupoid_compose,
104	"send_clone_fn::new": send_lift_fn_new,
105	"send_clone_fn::ref_new": send_ref_lift_fn_new,
106}, exclude {
107	// By-value non-dispatch free functions superseded by dispatch versions.
108	"contravariant::contramap",
109	"alt::alt",
110	"apply_first::apply_first",
111	"apply_second::apply_second",
112	"bifoldable::bi_fold_left",
113	"bifoldable::bi_fold_map",
114	"bifoldable::bi_fold_right",
115	"bifunctor::bimap",
116	"bitraversable::bi_traverse",
117	"compactable::compact",
118	"compactable::separate",
119	"filterable::filter",
120	"filterable::filter_map",
121	"filterable::partition",
122	"filterable::partition_map",
123	"filterable_with_index::filter_map_with_index",
124	"filterable_with_index::filter_with_index",
125	"filterable_with_index::partition_map_with_index",
126	"filterable_with_index::partition_with_index",
127	"foldable_with_index::fold_left_with_index",
128	"foldable_with_index::fold_map_with_index",
129	"foldable_with_index::fold_right_with_index",
130	"functor_with_index::map_with_index",
131	"semimonad::join",
132	"traversable::traverse",
133	"traversable_with_index::traverse_with_index",
134	"witherable::wilt",
135	"witherable::wither",
136	// By-ref non-dispatch free functions superseded by dispatch versions.
137	"ref_alt::ref_alt",
138	"ref_apply_first::ref_apply_first",
139	"ref_apply_second::ref_apply_second",
140	"ref_bifunctor::ref_bimap",
141	"ref_bifoldable::ref_bi_fold_left",
142	"ref_bifoldable::ref_bi_fold_map",
143	"ref_bifoldable::ref_bi_fold_right",
144	"ref_bitraversable::ref_bi_traverse",
145	"ref_compactable::ref_compact",
146	"ref_compactable::ref_separate",
147	"ref_filterable::ref_filter",
148	"ref_filterable::ref_filter_map",
149	"ref_filterable::ref_partition",
150	"ref_filterable::ref_partition_map",
151	"ref_filterable_with_index::ref_filter_with_index",
152	"ref_filterable_with_index::ref_filter_map_with_index",
153	"ref_filterable_with_index::ref_partition_with_index",
154	"ref_filterable_with_index::ref_partition_map_with_index",
155	"ref_foldable_with_index::ref_fold_left_with_index",
156	"ref_foldable_with_index::ref_fold_map_with_index",
157	"ref_foldable_with_index::ref_fold_right_with_index",
158	"ref_functor_with_index::ref_map_with_index",
159	"ref_semimonad::ref_join",
160	"ref_traversable_with_index::ref_traverse_with_index",
161	"ref_witherable::ref_wilt",
162	"ref_witherable::ref_wither",
163});
164/// Explicit dispatch functions requiring a Brand turbofish.
165///
166/// For most use cases, prefer the inference-enabled wrappers from the parent
167/// [`functions`](crate::functions) module.
168pub mod explicit {
169	pub use crate::dispatch::{
170		alt::explicit::alt,
171		apply_first::explicit::apply_first,
172		apply_second::explicit::apply_second,
173		bifoldable::explicit::{
174			bi_fold_left,
175			bi_fold_map,
176			bi_fold_right,
177		},
178		bifunctor::explicit::bimap,
179		bitraversable::explicit::bi_traverse,
180		compactable::explicit::{
181			compact,
182			separate,
183		},
184		contravariant::explicit::contramap,
185		filterable::explicit::{
186			filter,
187			filter_map,
188			partition,
189			partition_map,
190		},
191		filterable_with_index::explicit::{
192			filter_map_with_index,
193			filter_with_index,
194			partition_map_with_index,
195			partition_with_index,
196		},
197		foldable::explicit::{
198			fold_left,
199			fold_map,
200			fold_right,
201		},
202		foldable_with_index::explicit::{
203			fold_left_with_index,
204			fold_map_with_index,
205			fold_right_with_index,
206		},
207		functor::explicit::map,
208		functor_with_index::explicit::map_with_index,
209		lift::explicit::{
210			lift2,
211			lift3,
212			lift4,
213			lift5,
214		},
215		semimonad::explicit::{
216			bind,
217			bind_flipped,
218			join,
219		},
220		traversable::explicit::traverse,
221		traversable_with_index::explicit::traverse_with_index,
222		witherable::explicit::{
223			wilt,
224			wither,
225		},
226	};
227}
228
229// Functions without dispatch wrappers.
230pub use crate::dispatch::semimonad::{
231	compose_kleisli,
232	compose_kleisli_flipped,
233};
234// Re-exports from other modules.
235pub use crate::types::{
236	lazy::{
237		arc_lazy_fix,
238		rc_lazy_fix,
239	},
240	optics::{
241		optics_as_index,
242		optics_compose,
243		optics_indexed_fold_map,
244		optics_indexed_over,
245		optics_indexed_preview,
246		optics_indexed_set,
247		optics_indexed_view,
248		optics_reindexed,
249		optics_un_index,
250		positions,
251	},
252};
253
254/// Composes two functions.
255///
256/// Takes two functions, `f` and `g`, and returns a new function that applies `g` to its argument,
257/// and then applies `f` to the result. This is equivalent to the mathematical composition `f ∘ g`.
258#[document_signature]
259///
260#[document_type_parameters(
261	"The input type of the inner function `g`.",
262	"The output type of `g` and the input type of `f`.",
263	"The output type of the outer function `f`."
264)]
265///
266#[document_parameters(
267	"The outer function to apply second.",
268	"The inner function to apply first.",
269	"The argument to be passed to the composed function."
270)]
271/// ### Returns
272///
273/// A new function that takes an `A` and returns a `C`.
274///
275/// ### Examples
276///
277/// ```rust
278/// use fp_library::functions::*;
279///
280/// let add_one = |x: i32| x + 1;
281/// let times_two = |x: i32| x * 2;
282/// let times_two_add_one = compose(add_one, times_two);
283///
284/// // 3 * 2 + 1 = 7
285/// assert_eq!(times_two_add_one(3), 7);
286/// ```
287pub fn compose<A, B, C>(
288	f: impl Fn(B) -> C,
289	g: impl Fn(A) -> B,
290) -> impl Fn(A) -> C {
291	move |a| f(g(a))
292}
293
294/// Creates a constant function.
295///
296/// Returns a function that ignores its argument and always returns the provided value `a`.
297/// This is useful when a function is expected but a constant value is needed.
298#[document_signature]
299///
300#[document_type_parameters(
301	"The type of the value to return.",
302	"The type of the argument to ignore."
303)]
304///
305#[document_parameters(
306	"The value to be returned by the constant function.",
307	"The argument to be ignored."
308)]
309/// ### Returns
310///
311/// The first parameter.
312///
313/// ### Examples
314///
315/// ```rust
316/// use fp_library::functions::*;
317///
318/// assert_eq!(constant(true, false), true);
319/// ```
320pub fn constant<A: Clone, B>(
321	a: A,
322	_b: B,
323) -> A {
324	a
325}
326
327/// Flips the arguments of a binary function.
328///
329/// Returns a new function that takes its arguments in the reverse order of the input function `f`.
330/// If `f` takes `(a, b)`, the returned function takes `(b, a)`.
331#[document_signature]
332///
333#[document_type_parameters(
334	"The type of the first argument of the input function.",
335	"The type of the second argument of the input function.",
336	"The return type of the function."
337)]
338///
339#[document_parameters(
340	"A binary function.",
341	"The second argument (which will be passed as the first to `f`).",
342	"The first argument (which will be passed as the second to `f`)."
343)]
344/// ### Returns
345///
346/// A version of `f` that takes its arguments in reverse.
347///
348/// ### Examples
349///
350/// ```rust
351/// use fp_library::functions::*;
352///
353/// let subtract = |a, b| a - b;
354///
355/// // 0 - 1 = -1
356/// assert_eq!(flip(subtract)(1, 0), -1);
357/// ```
358pub fn flip<A, B, C>(f: impl Fn(A, B) -> C) -> impl Fn(B, A) -> C {
359	move |b, a| f(a, b)
360}
361
362/// The identity function.
363///
364/// Returns its input argument as is. This is often used as a default or placeholder function.
365#[document_signature]
366///
367#[document_type_parameters("The type of the value.")]
368///
369#[document_parameters("A value.")]
370///
371/// ### Returns
372///
373/// The same value `a`.
374///
375/// ### Examples
376///
377/// ```rust
378/// use fp_library::functions::*;
379///
380/// assert_eq!(identity(()), ());
381/// ```
382pub fn identity<A>(a: A) -> A {
383	a
384}
385
386/// Applies a binary function after projecting both arguments through a common function.
387///
388/// `on(f, g, x, y)` computes `f(g(x), g(y))`. This is useful for changing the domain
389/// of a binary operation.
390#[document_signature]
391///
392#[document_type_parameters(
393	"The type of the original arguments.",
394	"The type of the projected arguments.",
395	"The result type."
396)]
397///
398#[document_parameters(
399	"The binary function to apply to the projected values.",
400	"The projection function applied to both arguments.",
401	"The first argument.",
402	"The second argument."
403)]
404///
405#[document_returns("The result of applying `f` to the projected values.")]
406#[document_examples]
407///
408/// ```
409/// use fp_library::functions::*;
410///
411/// // Compare by absolute value
412/// let max_by_abs = on(|a: i32, b: i32| a.max(b), |x: i32| x.abs(), -5, 3);
413/// assert_eq!(max_by_abs, 5);
414///
415/// // Sum the lengths of two strings
416/// let sum_lens = on(|a: usize, b: usize| a + b, |s: &str| s.len(), "hello", "hi");
417/// assert_eq!(sum_lens, 7);
418/// ```
419pub fn on<A, B, C>(
420	f: impl Fn(B, B) -> C,
421	g: impl Fn(A) -> B,
422	x: A,
423	y: A,
424) -> C {
425	f(g(x), g(y))
426}