1use crate::{
7 Apply,
8 classes::{clonable_fn::ClonableFn, monoid::Monoid, semigroup::Semigroup},
9 functions::identity,
10};
11use std::{
12 fmt::{self, Debug, Formatter},
13 hash::Hash,
14};
15
16pub struct Endofunction<'a, FnBrand: ClonableFn, A>(
27 pub Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)),
28);
29
30impl<'a, FnBrand: ClonableFn, A> Endofunction<'a, FnBrand, A> {
31 pub fn new(
63 f: Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A))
64 ) -> Self {
65 Self(f)
66 }
67}
68
69impl<'a, FnBrand: ClonableFn, A> Clone for Endofunction<'a, FnBrand, A> {
70 fn clone(&self) -> Self {
71 Self::new(self.0.clone())
72 }
73}
74
75impl<'a, FnBrand: ClonableFn, A> Debug for Endofunction<'a, FnBrand, A>
76where
77 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): Debug,
78{
79 fn fmt(
80 &self,
81 fmt: &mut Formatter<'_>,
82 ) -> fmt::Result {
83 fmt.debug_tuple("Endofunction").field(&self.0).finish()
84 }
85}
86
87impl<'a, FnBrand: ClonableFn, A> Eq for Endofunction<'a, FnBrand, A> where
88 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): Eq
89{
90}
91
92impl<'a, FnBrand: ClonableFn, A> Hash for Endofunction<'a, FnBrand, A>
93where
94 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): Hash,
95{
96 fn hash<H: std::hash::Hasher>(
97 &self,
98 state: &mut H,
99 ) {
100 self.0.hash(state);
101 }
102}
103
104impl<'a, FnBrand: ClonableFn, A> Ord for Endofunction<'a, FnBrand, A>
105where
106 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): Ord,
107{
108 fn cmp(
109 &self,
110 other: &Self,
111 ) -> std::cmp::Ordering {
112 self.0.cmp(&other.0)
113 }
114}
115
116impl<'a, FnBrand: ClonableFn, A> PartialEq for Endofunction<'a, FnBrand, A>
117where
118 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): PartialEq,
119{
120 fn eq(
121 &self,
122 other: &Self,
123 ) -> bool {
124 self.0 == other.0
125 }
126}
127
128impl<'a, FnBrand: ClonableFn, A> PartialOrd for Endofunction<'a, FnBrand, A>
129where
130 Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, A)): PartialOrd,
131{
132 fn partial_cmp(
133 &self,
134 other: &Self,
135 ) -> Option<std::cmp::Ordering> {
136 self.0.partial_cmp(&other.0)
137 }
138}
139
140impl<'a, FnBrand: 'a + ClonableFn, A: 'a> Semigroup for Endofunction<'a, FnBrand, A> {
141 fn append(
176 a: Self,
177 b: Self,
178 ) -> Self {
179 let f = a.0;
180 let g = b.0;
181 Self::new(<FnBrand as ClonableFn>::new(move |x| f(g(x))))
183 }
184}
185
186impl<'a, FnBrand: 'a + ClonableFn, A: 'a> Monoid for Endofunction<'a, FnBrand, A> {
187 fn empty() -> Self {
210 Self::new(<FnBrand as ClonableFn>::new(identity))
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::{
218 brands::RcFnBrand,
219 classes::{clonable_fn::ClonableFn, monoid::empty, semigroup::append},
220 };
221 use quickcheck_macros::quickcheck;
222
223 #[quickcheck]
227 fn semigroup_associativity(val: i32) -> bool {
228 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
229 x.wrapping_add(1)
230 }));
231 let g = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
232 x.wrapping_mul(2)
233 }));
234 let h = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
235 x.wrapping_sub(3)
236 }));
237
238 let lhs = append(f.clone(), append(g.clone(), h.clone()));
239 let rhs = append(append(f, g), h);
240
241 lhs.0(val) == rhs.0(val)
242 }
243
244 #[quickcheck]
248 fn monoid_left_identity(val: i32) -> bool {
249 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
250 x.wrapping_add(1)
251 }));
252 let id = empty::<Endofunction<RcFnBrand, i32>>();
253
254 let res = append(id, f.clone());
255 res.0(val) == f.0(val)
256 }
257
258 #[quickcheck]
260 fn monoid_right_identity(val: i32) -> bool {
261 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
262 x.wrapping_add(1)
263 }));
264 let id = empty::<Endofunction<RcFnBrand, i32>>();
265
266 let res = append(f.clone(), id);
267 res.0(val) == f.0(val)
268 }
269}