1use crate::{
4 Apply,
5 classes::{category::Category, monoid::Monoid, semigroup::Semigroup},
6 kinds::*,
7};
8use std::{
9 fmt::{self, Debug, Formatter},
10 hash::Hash,
11};
12
13pub struct Endomorphism<'a, C: Category, A>(pub Apply!(brand: C, signature: ('a, A, A)));
25
26impl<'a, C: Category, A> Endomorphism<'a, C, A> {
27 pub fn new(f: Apply!(brand: C, signature: ('a, A, A))) -> Self {
41 Self(f)
42 }
43}
44
45impl<'a, C: Category, A> Clone for Endomorphism<'a, C, A>
46where
47 Apply!(brand: C, signature: ('a, A, A)): Clone,
48{
49 fn clone(&self) -> Self {
50 Self::new(self.0.clone())
51 }
52}
53
54impl<'a, C: Category, A> Debug for Endomorphism<'a, C, A>
55where
56 Apply!(brand: C, signature: ('a, A, A)): Debug,
57{
58 fn fmt(
59 &self,
60 fmt: &mut Formatter<'_>,
61 ) -> fmt::Result {
62 fmt.debug_tuple("Endomorphism").field(&self.0).finish()
63 }
64}
65
66impl<'a, C: Category, A> Eq for Endomorphism<'a, C, A> where
67 Apply!(brand: C, signature: ('a, A, A)): Eq
68{
69}
70
71impl<'a, C: Category, A> Hash for Endomorphism<'a, C, A>
72where
73 Apply!(brand: C, signature: ('a, A, A)): Hash,
74{
75 fn hash<H: std::hash::Hasher>(
76 &self,
77 state: &mut H,
78 ) {
79 self.0.hash(state);
80 }
81}
82
83impl<'a, C: Category, A> Ord for Endomorphism<'a, C, A>
84where
85 Apply!(brand: C, signature: ('a, A, A)): Ord,
86{
87 fn cmp(
88 &self,
89 other: &Self,
90 ) -> std::cmp::Ordering {
91 self.0.cmp(&other.0)
92 }
93}
94
95impl<'a, C: Category, A> PartialEq for Endomorphism<'a, C, A>
96where
97 Apply!(brand: C, signature: ('a, A, A)): PartialEq,
98{
99 fn eq(
100 &self,
101 other: &Self,
102 ) -> bool {
103 self.0 == other.0
104 }
105}
106
107impl<'a, C: Category, A> PartialOrd for Endomorphism<'a, C, A>
108where
109 Apply!(brand: C, signature: ('a, A, A)): PartialOrd,
110{
111 fn partial_cmp(
112 &self,
113 other: &Self,
114 ) -> Option<std::cmp::Ordering> {
115 self.0.partial_cmp(&other.0)
116 }
117}
118
119impl<'a, C: Category, A: 'a> Semigroup for Endomorphism<'a, C, A> {
120 fn append(
149 a: Self,
150 b: Self,
151 ) -> Self {
152 Self::new(C::compose(a.0, b.0))
153 }
154}
155
156impl<'a, C: Category, A: 'a> Monoid for Endomorphism<'a, C, A> {
157 fn empty() -> Self {
178 Self::new(C::identity())
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use crate::{
186 brands::RcFnBrand,
187 classes::{clonable_fn::ClonableFn, monoid::empty, semigroup::append},
188 };
189 use quickcheck_macros::quickcheck;
190
191 #[quickcheck]
195 fn semigroup_associativity(val: i32) -> bool {
196 let f = Endomorphism::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
197 x.wrapping_add(1)
198 }));
199 let g = Endomorphism::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
200 x.wrapping_mul(2)
201 }));
202 let h = Endomorphism::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
203 x.wrapping_sub(3)
204 }));
205
206 let lhs = append(f.clone(), append(g.clone(), h.clone()));
207 let rhs = append(append(f, g), h);
208
209 lhs.0(val) == rhs.0(val)
210 }
211
212 #[quickcheck]
216 fn monoid_left_identity(val: i32) -> bool {
217 let f = Endomorphism::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
218 x.wrapping_add(1)
219 }));
220 let id = empty::<Endomorphism<RcFnBrand, i32>>();
221
222 let res = append(id, f.clone());
223 res.0(val) == f.0(val)
224 }
225
226 #[quickcheck]
228 fn monoid_right_identity(val: i32) -> bool {
229 let f = Endomorphism::<RcFnBrand, _>::new(<RcFnBrand as ClonableFn>::new(|x: i32| {
230 x.wrapping_add(1)
231 }));
232 let id = empty::<Endomorphism<RcFnBrand, i32>>();
233
234 let res = append(f.clone(), id);
235 res.0(val) == f.0(val)
236 }
237}