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}