1use core::marker::PhantomData;
2
3pub trait Property {
8 const NAME: &'static str;
10}
11
12pub trait Implies<Q> {}
14
15pub struct IsAssociative;
21impl Property for IsAssociative {
22 const NAME: &'static str = "associativity";
23}
24
25pub struct HasLeftIdentity;
27impl Property for HasLeftIdentity {
28 const NAME: &'static str = "left identity";
29}
30
31pub struct HasRightIdentity;
33impl Property for HasRightIdentity {
34 const NAME: &'static str = "right identity";
35}
36
37pub struct IsMonoid;
39impl Property for IsMonoid {
40 const NAME: &'static str = "monoid";
41}
42
43impl Implies<IsAssociative> for IsMonoid {}
45impl Implies<HasLeftIdentity> for IsMonoid {}
46impl Implies<HasRightIdentity> for IsMonoid {}
47
48pub struct HasLeftInverse;
54impl Property for HasLeftInverse {
55 const NAME: &'static str = "left inverse";
56}
57
58pub struct HasRightInverse;
60impl Property for HasRightInverse {
61 const NAME: &'static str = "right inverse";
62}
63
64pub struct IsGroup;
66impl Property for IsGroup {
67 const NAME: &'static str = "group";
68}
69
70impl Implies<IsMonoid> for IsGroup {}
71impl Implies<IsAssociative> for IsGroup {}
72impl Implies<HasLeftIdentity> for IsGroup {}
73impl Implies<HasRightIdentity> for IsGroup {}
74impl Implies<HasLeftInverse> for IsGroup {}
75impl Implies<HasRightInverse> for IsGroup {}
76
77pub struct IsCommutative;
83impl Property for IsCommutative {
84 const NAME: &'static str = "commutativity";
85}
86
87pub struct IsAbelianGroup;
89impl Property for IsAbelianGroup {
90 const NAME: &'static str = "abelian group";
91}
92
93impl Implies<IsGroup> for IsAbelianGroup {}
94impl Implies<IsMonoid> for IsAbelianGroup {}
95impl Implies<IsAssociative> for IsAbelianGroup {}
96impl Implies<IsCommutative> for IsAbelianGroup {}
97impl Implies<HasLeftInverse> for IsAbelianGroup {}
98impl Implies<HasRightInverse> for IsAbelianGroup {}
99impl Implies<HasLeftIdentity> for IsAbelianGroup {}
100impl Implies<HasRightIdentity> for IsAbelianGroup {}
101
102pub struct AdditivelyCommutative;
108impl Property for AdditivelyCommutative {
109 const NAME: &'static str = "additively commutative";
110}
111
112pub struct IsDistributive;
114impl Property for IsDistributive {
115 const NAME: &'static str = "distributive";
116}
117
118pub struct ZeroAnnihilates;
120impl Property for ZeroAnnihilates {
121 const NAME: &'static str = "zero annihilation";
122}
123
124pub struct IsSemiring;
126impl Property for IsSemiring {
127 const NAME: &'static str = "semiring";
128}
129
130impl Implies<AdditivelyCommutative> for IsSemiring {}
131impl Implies<IsDistributive> for IsSemiring {}
132impl Implies<ZeroAnnihilates> for IsSemiring {}
133
134pub struct IsRing;
136impl Property for IsRing {
137 const NAME: &'static str = "ring";
138}
139
140impl Implies<IsSemiring> for IsRing {}
141impl Implies<AdditivelyCommutative> for IsRing {}
142impl Implies<IsDistributive> for IsRing {}
143
144pub struct IsField;
146impl Property for IsField {
147 const NAME: &'static str = "field";
148}
149
150impl Implies<IsRing> for IsField {}
151impl Implies<IsSemiring> for IsField {}
152
153pub struct IsIdempotent;
159impl Property for IsIdempotent {
160 const NAME: &'static str = "idempotent";
161}
162
163pub struct IsAbsorptive;
165impl Property for IsAbsorptive {
166 const NAME: &'static str = "absorptive";
167}
168
169pub struct IsLattice;
171impl Property for IsLattice {
172 const NAME: &'static str = "lattice";
173}
174
175impl Implies<IsIdempotent> for IsLattice {}
176impl Implies<IsAbsorptive> for IsLattice {}
177impl Implies<IsCommutative> for IsLattice {}
178impl Implies<IsAssociative> for IsLattice {}
179
180pub struct IsBoundedLattice;
182impl Property for IsBoundedLattice {
183 const NAME: &'static str = "bounded lattice";
184}
185
186impl Implies<IsLattice> for IsBoundedLattice {}
187impl Implies<IsIdempotent> for IsBoundedLattice {}
188impl Implies<IsAbsorptive> for IsBoundedLattice {}
189
190pub struct FunctorIdentity;
196impl Property for FunctorIdentity {
197 const NAME: &'static str = "functor identity";
198}
199
200pub struct FunctorComposition;
202impl Property for FunctorComposition {
203 const NAME: &'static str = "functor composition";
204}
205
206pub struct IsLawfulFunctor;
208impl Property for IsLawfulFunctor {
209 const NAME: &'static str = "lawful functor";
210}
211
212impl Implies<FunctorIdentity> for IsLawfulFunctor {}
213impl Implies<FunctorComposition> for IsLawfulFunctor {}
214
215pub struct MonadLeftIdentity;
217impl Property for MonadLeftIdentity {
218 const NAME: &'static str = "monad left identity";
219}
220
221pub struct MonadRightIdentity;
223impl Property for MonadRightIdentity {
224 const NAME: &'static str = "monad right identity";
225}
226
227pub struct MonadAssociativity;
229impl Property for MonadAssociativity {
230 const NAME: &'static str = "monad associativity";
231}
232
233pub struct IsLawfulMonad;
235impl Property for IsLawfulMonad {
236 const NAME: &'static str = "lawful monad";
237}
238
239impl Implies<IsLawfulFunctor> for IsLawfulMonad {}
240impl Implies<MonadLeftIdentity> for IsLawfulMonad {}
241impl Implies<MonadRightIdentity> for IsLawfulMonad {}
242impl Implies<MonadAssociativity> for IsLawfulMonad {}
243
244pub struct And<P, Q>(PhantomData<(P, Q)>);
257impl<P: Property, Q: Property> Property for And<P, Q> {
258 const NAME: &'static str = "conjunction";
259}
260
261impl<P, Q> Implies<P> for And<P, Q> {}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn property_names() {
270 assert_eq!(IsAssociative::NAME, "associativity");
271 assert_eq!(IsMonoid::NAME, "monoid");
272 assert_eq!(IsGroup::NAME, "group");
273 assert_eq!(IsAbelianGroup::NAME, "abelian group");
274 assert_eq!(IsSemiring::NAME, "semiring");
275 assert_eq!(IsRing::NAME, "ring");
276 assert_eq!(IsField::NAME, "field");
277 assert_eq!(IsLattice::NAME, "lattice");
278 assert_eq!(IsBoundedLattice::NAME, "bounded lattice");
279 assert_eq!(IsLawfulFunctor::NAME, "lawful functor");
280 assert_eq!(IsLawfulMonad::NAME, "lawful monad");
281 }
282
283 fn _assert_implies<P: Implies<Q>, Q>() {}
285
286 #[test]
287 fn implication_lattice_compiles() {
288 _assert_implies::<IsMonoid, IsAssociative>();
289 _assert_implies::<IsMonoid, HasLeftIdentity>();
290 _assert_implies::<IsGroup, IsMonoid>();
291 _assert_implies::<IsGroup, IsAssociative>();
292 _assert_implies::<IsAbelianGroup, IsGroup>();
293 _assert_implies::<IsAbelianGroup, IsCommutative>();
294 _assert_implies::<IsField, IsRing>();
295 _assert_implies::<IsRing, IsSemiring>();
296 _assert_implies::<IsBoundedLattice, IsLattice>();
297 _assert_implies::<IsLawfulMonad, IsLawfulFunctor>();
298 _assert_implies::<And<IsAssociative, IsCommutative>, IsAssociative>();
299 }
301}