1use core::fmt;
4use std::{
5 fmt::{Debug, Formatter},
6 hash::Hash,
7 marker::PhantomData,
8};
9
10use crate::{
11 classes::{
12 Category, ClonableFn, Monoid, Semigroup, clonable_fn::ApplyFn, monoid::Monoid1L0T,
13 semigroup::Semigroup1L0T,
14 },
15 hkt::{Apply1L2T, Kind1L0T},
16};
17
18pub struct Endomorphism<'a, CategoryBrand: Category, A: 'a>(pub Apply1L2T<'a, CategoryBrand, A, A>);
30
31impl<'a, CategoryBrand: Category, A> Endomorphism<'a, CategoryBrand, A> {
32 pub fn new(a: Apply1L2T<'a, CategoryBrand, A, A>) -> Self {
33 Self(a)
34 }
35}
36
37impl<'a, CategoryBrand: Category, A> Clone for Endomorphism<'a, CategoryBrand, A>
38where
39 Apply1L2T<'a, CategoryBrand, A, A>: Clone,
40{
41 fn clone(&self) -> Self {
42 Endomorphism(self.0.clone())
43 }
44}
45
46impl<'a, CategoryBrand: Category, A> Debug for Endomorphism<'a, CategoryBrand, A>
47where
48 Apply1L2T<'a, CategoryBrand, A, A>: Debug,
49{
50 fn fmt(
51 &self,
52 fmt: &mut Formatter<'_>,
53 ) -> fmt::Result {
54 fmt.debug_tuple("Endomorphism").field(&self.0).finish()
55 }
56}
57
58impl<'a, CategoryBrand: 'a + Category, A> Eq for Endomorphism<'a, CategoryBrand, A> where
59 Apply1L2T<'a, CategoryBrand, A, A>: Eq
60{
61}
62
63impl<'a, CategoryBrand: Category, A> Hash for Endomorphism<'a, CategoryBrand, A>
64where
65 Apply1L2T<'a, CategoryBrand, A, A>: Hash,
66{
67 fn hash<H: std::hash::Hasher>(
68 &self,
69 state: &mut H,
70 ) {
71 self.0.hash(state);
72 }
73}
74
75impl<'a, CategoryBrand: 'a + Category, A> Ord for Endomorphism<'a, CategoryBrand, A>
76where
77 Apply1L2T<'a, CategoryBrand, A, A>: Ord,
78{
79 fn cmp(
80 &self,
81 other: &Self,
82 ) -> std::cmp::Ordering {
83 self.0.cmp(&other.0)
84 }
85}
86
87impl<'a, CategoryBrand: Category, A> PartialEq for Endomorphism<'a, CategoryBrand, A>
88where
89 Apply1L2T<'a, CategoryBrand, A, A>: PartialEq,
90{
91 fn eq(
92 &self,
93 other: &Self,
94 ) -> bool {
95 self.0 == other.0
96 }
97}
98
99impl<'a, CategoryBrand: Category, A> PartialOrd for Endomorphism<'a, CategoryBrand, A>
100where
101 Apply1L2T<'a, CategoryBrand, A, A>: PartialOrd,
102{
103 fn partial_cmp(
104 &self,
105 other: &Self,
106 ) -> Option<std::cmp::Ordering> {
107 self.0.partial_cmp(&other.0)
108 }
109}
110
111impl<'b, CategoryBrand: 'b + Category, A> Semigroup<'b> for Endomorphism<'b, CategoryBrand, A>
112where
113 Apply1L2T<'b, CategoryBrand, A, A>: Clone,
114{
115 fn append<'a, ClonableFnBrand: 'a + 'b + ClonableFn>(
116 a: Self
117 ) -> ApplyFn<'a, ClonableFnBrand, Self, Self>
118 where
119 Self: Sized,
120 'b: 'a,
121 {
122 ClonableFnBrand::new(move |b: Self| {
123 Endomorphism(CategoryBrand::compose::<'b, ClonableFnBrand, _, _, _>(a.0.clone())(b.0))
124 })
125 }
126}
127
128impl<'a, CategoryBrand: 'a + Category, A> Monoid<'a> for Endomorphism<'a, CategoryBrand, A>
129where
130 Apply1L2T<'a, CategoryBrand, A, A>: Clone,
131{
132 fn empty() -> Self {
133 Endomorphism(CategoryBrand::identity::<'a, _>())
134 }
135}
136
137#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
138pub struct EndomorphismBrand<CategoryBrand: Category, A>(PhantomData<(CategoryBrand, A)>);
139
140impl<CategoryBrand: Category, A: 'static> Kind1L0T for EndomorphismBrand<CategoryBrand, A> {
141 type Output<'a> = Endomorphism<'a, CategoryBrand, A>;
142}
143
144impl<CategoryBrand: 'static + Category, A: 'static> Semigroup1L0T
145 for EndomorphismBrand<CategoryBrand, A>
146where
147 for<'a> Apply1L2T<'a, CategoryBrand, A, A>: Clone,
148{
149}
150
151impl<CategoryBrand: 'static + Category, A: 'static> Monoid1L0T
152 for EndomorphismBrand<CategoryBrand, A>
153where
154 for<'a> Apply1L2T<'a, CategoryBrand, A, A>: Clone,
155{
156}