fp_library/types/
rc_fn.rs

1//! Reference-counted function wrapper.
2//!
3//! This module defines the [`RcFnBrand`] struct, which provides implementations for reference-counted closures (`Rc<dyn Fn(A) -> B>`).
4//! It implements [`Function`], [`ClonableFn`], [`Semigroupoid`], and [`Category`].
5
6use crate::{
7	Apply,
8	brands::RcFnBrand,
9	classes::{
10		category::Category, clonable_fn::ClonableFn, function::Function, semigroupoid::Semigroupoid,
11	},
12	impl_kind,
13	kinds::*,
14};
15use std::rc::Rc;
16
17impl_kind! {
18	for RcFnBrand {
19		type Of<'a, A, B> = Rc<dyn 'a + Fn(A) -> B>;
20	}
21}
22
23impl Function for RcFnBrand {
24	type Of<'a, A, B> = Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, A, B>);
25
26	/// Creates a new function wrapper.
27	///
28	/// This function wraps the provided closure `f` into an `Rc`-wrapped function.
29	///
30	/// ### Type Signature
31	///
32	/// `forall a b. Function RcFnBrand => (a -> b) -> RcFnBrand a b`
33	///
34	/// ### Type Parameters
35	///
36	/// * `A`: The input type of the function.
37	/// * `B`: The output type of the function.
38	///
39	/// ### Parameters
40	///
41	/// * `f`: The closure to wrap.
42	///
43	/// ### Returns
44	///
45	/// The wrapped function.
46	///
47	/// ### Examples
48	///
49	/// ```
50	/// use fp_library::brands::RcFnBrand;
51	/// use fp_library::classes::function::Function;
52	///
53	/// let f = <RcFnBrand as Function>::new(|x: i32| x * 2);
54	/// assert_eq!(f(5), 10);
55	/// ```
56	fn new<'a, A, B>(f: impl 'a + Fn(A) -> B) -> <Self as Function>::Of<'a, A, B> {
57		Rc::new(f)
58	}
59}
60
61impl ClonableFn for RcFnBrand {
62	type Of<'a, A, B> = Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, A, B>);
63
64	/// Creates a new clonable function wrapper.
65	///
66	/// This function wraps the provided closure `f` into an `Rc`-wrapped clonable function.
67	///
68	/// ### Type Signature
69	///
70	/// `forall a b. ClonableFn RcFnBrand => (a -> b) -> RcFnBrand a b`
71	///
72	/// ### Type Parameters
73	///
74	/// * `A`: The input type of the function.
75	/// * `B`: The output type of the function.
76	///
77	/// ### Parameters
78	///
79	/// * `f`: The closure to wrap.
80	///
81	/// ### Returns
82	///
83	/// The wrapped clonable function.
84	///
85	/// ### Examples
86	///
87	/// ```
88	/// use fp_library::brands::RcFnBrand;
89	/// use fp_library::classes::clonable_fn::ClonableFn;
90	///
91	/// let f = <RcFnBrand as ClonableFn>::new(|x: i32| x * 2);
92	/// assert_eq!(f(5), 10);
93	/// ```
94	fn new<'a, A, B>(f: impl 'a + Fn(A) -> B) -> <Self as ClonableFn>::Of<'a, A, B> {
95		Rc::new(f)
96	}
97}
98
99impl Semigroupoid for RcFnBrand {
100	/// Takes morphisms `f` and `g` and returns the morphism `f . g` (`f` composed with `g`).
101	///
102	/// This method composes two `Rc`-wrapped functions `f` and `g` to produce a new function that represents the application of `g` followed by `f`.
103	///
104	/// ### Type Signature
105	///
106	/// `forall b c d. Semigroupoid RcFnBrand => (RcFnBrand c d, RcFnBrand b c) -> RcFnBrand b d`
107	///
108	/// ### Type Parameters
109	///
110	/// * `B`: The source type of the first morphism.
111	/// * `C`: The target type of the first morphism and the source type of the second morphism.
112	/// * `D`: The target type of the second morphism.
113	///
114	/// ### Parameters
115	///
116	/// * `f`: The second morphism to apply (from C to D).
117	/// * `g`: The first morphism to apply (from B to C).
118	///
119	/// ### Returns
120	///
121	/// The composed morphism (from B to D).
122	///
123	/// ### Examples
124	///
125	/// ```
126	/// use fp_library::brands::RcFnBrand;
127	/// use fp_library::classes::semigroupoid::Semigroupoid;
128	/// use fp_library::classes::clonable_fn::ClonableFn;
129	///
130	/// let f = <RcFnBrand as ClonableFn>::new(|x: i32| x * 2);
131	/// let g = <RcFnBrand as ClonableFn>::new(|x: i32| x + 1);
132	/// let h = RcFnBrand::compose(f, g);
133	/// assert_eq!(h(5), 12); // (5 + 1) * 2
134	/// ```
135	fn compose<'a, B: 'a, C: 'a, D: 'a>(
136		f: Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, C, D>),
137		g: Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, B, C>),
138	) -> Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, B, D>) {
139		<Self as ClonableFn>::new(move |b| f(g(b)))
140	}
141}
142
143impl Category for RcFnBrand {
144	/// Returns the identity morphism.
145	///
146	/// The identity morphism is a function that maps every object to itself, wrapped in an `Rc`.
147	///
148	/// ### Type Signature
149	///
150	/// `forall a. Category RcFnBrand => () -> RcFnBrand a a`
151	///
152	/// ### Type Parameters
153	///
154	/// * `A`: The type of the object.
155	///
156	/// ### Returns
157	///
158	/// The identity morphism.
159	///
160	/// ### Examples
161	///
162	/// ```
163	/// use fp_library::brands::RcFnBrand;
164	/// use fp_library::classes::category::Category;
165	///
166	/// let id = RcFnBrand::identity::<i32>();
167	/// assert_eq!(id(5), 5);
168	/// ```
169	fn identity<'a, A>() -> Apply!(<Self as Kind!( type Of<'a, T, U>; )>::Of<'a, A, A>) {
170		Rc::new(|a| a)
171	}
172}
173
174#[cfg(test)]
175mod tests {
176	use super::*;
177	use crate::classes::{category::Category, clonable_fn::ClonableFn, semigroupoid::Semigroupoid};
178	use quickcheck_macros::quickcheck;
179
180	// Semigroupoid Laws
181
182	/// Tests the associativity law for Semigroupoid.
183	#[quickcheck]
184	fn semigroupoid_associativity(x: i32) -> bool {
185		let f = <RcFnBrand as ClonableFn>::new(|x: i32| x.wrapping_add(1));
186		let g = <RcFnBrand as ClonableFn>::new(|x: i32| x.wrapping_mul(2));
187		let h = <RcFnBrand as ClonableFn>::new(|x: i32| x.wrapping_sub(3));
188
189		let lhs = RcFnBrand::compose(f.clone(), RcFnBrand::compose(g.clone(), h.clone()));
190		let rhs = RcFnBrand::compose(RcFnBrand::compose(f, g), h);
191
192		lhs(x) == rhs(x)
193	}
194
195	// Category Laws
196
197	/// Tests the left identity law for Category.
198	#[quickcheck]
199	fn category_left_identity(x: i32) -> bool {
200		let f = <RcFnBrand as ClonableFn>::new(|x: i32| x.wrapping_add(1));
201		let id = RcFnBrand::identity::<i32>();
202
203		let lhs = RcFnBrand::compose(id, f.clone());
204		let rhs = f;
205
206		lhs(x) == rhs(x)
207	}
208
209	/// Tests the right identity law for Category.
210	#[quickcheck]
211	fn category_right_identity(x: i32) -> bool {
212		let f = <RcFnBrand as ClonableFn>::new(|x: i32| x.wrapping_add(1));
213		let id = RcFnBrand::identity::<i32>();
214
215		let lhs = RcFnBrand::compose(f.clone(), id);
216		let rhs = f;
217
218		lhs(x) == rhs(x)
219	}
220}