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 functions::{compose, identity},
16 hkt::Kind1L0T,
17};
18
19pub struct Endofunction<'a, ClonableFnBrand: ClonableFn, A: 'a>(
54 pub ApplyFn<'a, ClonableFnBrand, A, A>,
55);
56
57impl<'a, ClonableFnBrand: ClonableFn, A> Endofunction<'a, ClonableFnBrand, A> {
58 pub fn new(a: ApplyFn<'a, ClonableFnBrand, A, A>) -> Self {
59 Self(a)
60 }
61}
62
63impl<'a, ClonableFnBrand: ClonableFn, A> Clone for Endofunction<'a, ClonableFnBrand, A> {
64 fn clone(&self) -> Self {
65 Endofunction(self.0.clone())
66 }
67}
68
69impl<'a, ClonableFnBrand: ClonableFn, A> Debug for Endofunction<'a, ClonableFnBrand, A>
70where
71 ApplyFn<'a, ClonableFnBrand, A, A>: Debug,
72{
73 fn fmt(
74 &self,
75 fmt: &mut Formatter<'_>,
76 ) -> fmt::Result {
77 fmt.debug_tuple("Endofunction").field(&self.0).finish()
78 }
79}
80
81impl<'a, ClonableFnBrand: ClonableFn, A> Eq for Endofunction<'a, ClonableFnBrand, A> where
82 ApplyFn<'a, ClonableFnBrand, A, A>: Eq
83{
84}
85
86impl<'a, ClonableFnBrand: ClonableFn, A> Hash for Endofunction<'a, ClonableFnBrand, A>
87where
88 ApplyFn<'a, ClonableFnBrand, A, A>: Hash,
89{
90 fn hash<H: std::hash::Hasher>(
91 &self,
92 state: &mut H,
93 ) {
94 self.0.hash(state);
95 }
96}
97
98impl<'a, ClonableFnBrand: ClonableFn, A> Ord for Endofunction<'a, ClonableFnBrand, A>
99where
100 ApplyFn<'a, ClonableFnBrand, A, A>: Ord,
101{
102 fn cmp(
103 &self,
104 other: &Self,
105 ) -> std::cmp::Ordering {
106 self.0.cmp(&other.0)
107 }
108}
109
110impl<'a, ClonableFnBrand: ClonableFn, A> PartialEq for Endofunction<'a, ClonableFnBrand, A>
111where
112 ApplyFn<'a, ClonableFnBrand, A, A>: PartialEq,
113{
114 fn eq(
115 &self,
116 other: &Self,
117 ) -> bool {
118 self.0 == other.0
119 }
120}
121
122impl<'a, ClonableFnBrand: ClonableFn, A> PartialOrd for Endofunction<'a, ClonableFnBrand, A>
123where
124 ApplyFn<'a, ClonableFnBrand, A, A>: PartialOrd,
125{
126 fn partial_cmp(
127 &self,
128 other: &Self,
129 ) -> Option<std::cmp::Ordering> {
130 self.0.partial_cmp(&other.0)
131 }
132}
133
134impl<'b, ClonableFnBrand: 'b + ClonableFn, A> Semigroup<'b>
135 for Endofunction<'b, ClonableFnBrand, A>
136{
137 fn append<'a, CFB: 'a + 'b + ClonableFn>(a: Self) -> ApplyFn<'a, CFB, Self, Self>
161 where
162 Self: Sized,
163 'b: 'a,
164 {
165 CFB::new(move |b: Self| {
166 Endofunction(compose::<'b, ClonableFnBrand, _, _, _>(a.0.clone())(b.0))
167 })
168 }
169}
170
171impl<'a, ClonableFnBrand: 'a + ClonableFn, A> Monoid<'a> for Endofunction<'a, ClonableFnBrand, A> {
172 fn empty() -> Self {
185 Endofunction(ClonableFnBrand::new(identity))
186 }
187}
188
189#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
190pub struct EndofunctionBrand<CategoryBrand: Category, A>(PhantomData<(CategoryBrand, A)>);
191
192impl<ClonableFnBrand: ClonableFn, A: 'static> Kind1L0T for EndofunctionBrand<ClonableFnBrand, A> {
193 type Output<'a> = Endofunction<'a, ClonableFnBrand, A>;
194}
195
196impl<ClonableFnBrand: 'static + ClonableFn, A: 'static> Semigroup1L0T
197 for EndofunctionBrand<ClonableFnBrand, A>
198where
199 for<'a> ApplyFn<'a, ClonableFnBrand, A, A>: Clone,
200{
201}
202
203impl<ClonableFnBrand: 'static + ClonableFn, A: 'static> Monoid1L0T
204 for EndofunctionBrand<ClonableFnBrand, A>
205where
206 for<'a> ApplyFn<'a, ClonableFnBrand, A, A>: Clone,
207{
208}