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//! };
15//!
16//! let f = |x: i32| x + 1;
17//! let g = |x: i32| x * 2;
18//! let h = compose(f, g);
19//!
20//! assert_eq!(map::<OptionBrand, _, _>(h, Some(5)), Some(11));
21//! ```
22
23use fp_macros::*;
24// Auto-generate re-exports, passing in aliases for conflicting names.
25fp_macros::generate_function_re_exports!("src/classes", {
26	"category::identity": category_identity,
27	"cloneable_fn::new": cloneable_fn_new,
28	"function::new": fn_new,
29	"pointer::new": pointer_new,
30	"ref_counted_pointer::cloneable_new": ref_counted_pointer_new,
31	"send_ref_counted_pointer::send_new": send_ref_counted_pointer_new,
32	"plus::empty": plus_empty,
33	"semigroupoid::compose": semigroupoid_compose,
34	"send_cloneable_fn::new": send_cloneable_fn_new,
35});
36pub use crate::types::optics::{
37	optics_as_index,
38	optics_compose,
39	optics_indexed_fold_map,
40	optics_indexed_over,
41	optics_indexed_preview,
42	optics_indexed_set,
43	optics_indexed_view,
44	optics_reindexed,
45	optics_un_index,
46	positions,
47};
48
49/// Composes two functions.
50///
51/// Takes two functions, `f` and `g`, and returns a new function that applies `g` to its argument,
52/// and then applies `f` to the result. This is equivalent to the mathematical composition `f ∘ g`.
53#[document_signature]
54///
55#[document_type_parameters(
56	"The input type of the inner function `g`.",
57	"The output type of `g` and the input type of `f`.",
58	"The output type of the outer function `f`."
59)]
60///
61#[document_parameters(
62	"The outer function to apply second.",
63	"The inner function to apply first.",
64	"The argument to be passed to the composed function."
65)]
66/// ### Returns
67///
68/// A new function that takes an `A` and returns a `C`.
69///
70/// ### Examples
71///
72/// ```rust
73/// use fp_library::functions::*;
74///
75/// let add_one = |x: i32| x + 1;
76/// let times_two = |x: i32| x * 2;
77/// let times_two_add_one = compose(add_one, times_two);
78///
79/// // 3 * 2 + 1 = 7
80/// assert_eq!(times_two_add_one(3), 7);
81/// ```
82pub fn compose<A, B, C>(
83	f: impl Fn(B) -> C,
84	g: impl Fn(A) -> B,
85) -> impl Fn(A) -> C {
86	move |a| f(g(a))
87}
88
89/// Creates a constant function.
90///
91/// Returns a function that ignores its argument and always returns the provided value `a`.
92/// This is useful when a function is expected but a constant value is needed.
93#[document_signature]
94///
95#[document_type_parameters(
96	"The type of the value to return.",
97	"The type of the argument to ignore."
98)]
99///
100#[document_parameters(
101	"The value to be returned by the constant function.",
102	"The argument to be ignored."
103)]
104/// ### Returns
105///
106/// The first parameter.
107///
108/// ### Examples
109///
110/// ```rust
111/// use fp_library::functions::*;
112///
113/// assert_eq!(constant(true, false), true);
114/// ```
115pub fn constant<A: Clone, B>(
116	a: A,
117	_b: B,
118) -> A {
119	a
120}
121
122/// Flips the arguments of a binary function.
123///
124/// Returns a new function that takes its arguments in the reverse order of the input function `f`.
125/// If `f` takes `(a, b)`, the returned function takes `(b, a)`.
126#[document_signature]
127///
128#[document_type_parameters(
129	"The type of the first argument of the input function.",
130	"The type of the second argument of the input function.",
131	"The return type of the function."
132)]
133///
134#[document_parameters(
135	"A binary function.",
136	"The second argument (which will be passed as the first to `f`).",
137	"The first argument (which will be passed as the second to `f`)."
138)]
139/// ### Returns
140///
141/// A version of `f` that takes its arguments in reverse.
142///
143/// ### Examples
144///
145/// ```rust
146/// use fp_library::functions::*;
147///
148/// let subtract = |a, b| a - b;
149///
150/// // 0 - 1 = -1
151/// assert_eq!(flip(subtract)(1, 0), -1);
152/// ```
153pub fn flip<A, B, C>(f: impl Fn(A, B) -> C) -> impl Fn(B, A) -> C {
154	move |b, a| f(a, b)
155}
156
157/// The identity function.
158///
159/// Returns its input argument as is. This is often used as a default or placeholder function.
160#[document_signature]
161///
162#[document_type_parameters("The type of the value.")]
163///
164#[document_parameters("A value.")]
165///
166/// ### Returns
167///
168/// The same value `a`.
169///
170/// ### Examples
171///
172/// ```rust
173/// use fp_library::functions::*;
174///
175/// assert_eq!(identity(()), ());
176/// ```
177pub fn identity<A>(a: A) -> A {
178	a
179}
180
181/// Applies a binary function after projecting both arguments through a common function.
182///
183/// `on(f, g, x, y)` computes `f(g(x), g(y))`. This is useful for changing the domain
184/// of a binary operation.
185#[document_signature]
186///
187#[document_type_parameters(
188	"The type of the original arguments.",
189	"The type of the projected arguments.",
190	"The result type."
191)]
192///
193#[document_parameters(
194	"The binary function to apply to the projected values.",
195	"The projection function applied to both arguments.",
196	"The first argument.",
197	"The second argument."
198)]
199///
200#[document_returns("The result of applying `f` to the projected values.")]
201#[document_examples]
202///
203/// ```
204/// use fp_library::functions::*;
205///
206/// // Compare by absolute value
207/// let max_by_abs = on(|a: i32, b: i32| a.max(b), |x: i32| x.abs(), -5, 3);
208/// assert_eq!(max_by_abs, 5);
209///
210/// // Sum the lengths of two strings
211/// let sum_lens = on(|a: usize, b: usize| a + b, |s: &str| s.len(), "hello", "hi");
212/// assert_eq!(sum_lens, 7);
213/// ```
214pub fn on<A, B, C>(
215	f: impl Fn(B, B) -> C,
216	g: impl Fn(A) -> B,
217	x: A,
218	y: A,
219) -> C {
220	f(g(x), g(y))
221}