Skip to main content

fp_library/
functions.rs

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