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