fp_library/types/
endomorphism.rs

1//! Implementations for [`Endomorphism`], a wrapper for endomorphisms (morphisms from an object to the same object) that enables monoidal operations.
2
3use 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
18/// A wrapper for endomorphisms (morphisms from an object to the same object) that enables monoidal operations.
19///
20/// `Endomorphism c a` represents a morphism `c a a` where `c` is a `Category`.
21/// For the category of functions, this represents functions of type `a -> a`.
22///
23/// It exists to provide a monoid instance where:
24///
25/// * The binary operation [append][Semigroup::append] is [morphism composition][crate::classes::Semigroupoid::compose].
26/// * The identity element [empty][Monoid::empty] is the [identity morphism][Category::identity].
27///
28/// The wrapped morphism can be accessed directly via the [`.0` field][Endomorphism#structfield.0].
29pub 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}