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}