Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit bdb848e

Browse files
committed
Make algebra interfaces verified by default (#4739)
Previously there were interfaces for Semigroup, Monoid, etc, that were just syntactic in nature, requiring only that operations like <+> or elements like neutral exist. There was a corresponding set of "verified" interfaces requiring that the expected laws actually hold. Thus Semigroup required that the <+> operation exist, while VerifiedSemigroup required that that operation actually be associative. Such an arrangement is annoying for two reasons. First, extra paperwork. If I want to show that something really is a semigroup, I have to write two implementation blocks, the "plain" version and the "verified" version. On the other side, if I want to add a new interface, then in order to keep with the existing style I need to write both a "plain" version and a "verified" version. In some cases, like AbelianGroup, the "plain" interface is empty, since it doesn't add any new syntactic elements. Second, proof. Suppose a type has been declared to be a Semigroup, but VerifiedSemigroup hasn't been implemented for it. What can be assumed about that type? Is its <+> operation associative or not? If it isn't, why call it a semigroup? If it is, why not prove it? And if it can't be proved, how do we know that it's true? The big selling point of Idris is its expressive type system and strong compile-time guarantees, so let's take advantage of that and verify by default. Fixing the interfaces is easy -- just move the "verified" requirements into the "plain" interface, and that's it. In some cases there were implementations of the "verified" interfaces, and those could also easily be copied over. More challenging are the cases for which there were no verified implementations. There are three ways of dealing with them: (1) Come up with the required proofs. This was done, for example, with `Semigroup a => Semigroup (Vect n a)` etc in contrib/Data/Matrix/Algebraic.idr, and also with easy ones like Maybe and Endomorphism. (2) Replace the interface with an "unverified" version, thereby highlighting the fact that the expected properties have not been proven. This was done with a few complicated data structures in contrib, like MaxiphobicHeap and SortedBag, as well as with primitive numeric types like Integer. (3) Assert without proof that the laws hold using believe_me and really_believe_me. This was done for cases in prelude and base for which proofs are impossible (eg String) or not obvious (eg Morphism and Kleislimorphism). Needless to say, these proofs should be implemented where possible. If these assertions are disliked, I would be happy to convert them to "unverified". Note that this change only applies to those interfaces that belong to "abstract algebra": semigroups, monoids, groups, and so on. There is a whole other set of "plain"/"verified" interfaces dealing with structures from "category theory". Those should also undergo this unification, but I don't know how to do it just yet.
1 parent 0417c53 commit bdb848e

File tree

25 files changed

+555
-337
lines changed

25 files changed

+555
-337
lines changed

libs/base/Control/Isomorphism.idr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,17 @@ Category Iso where
4141
Semigroup (Iso a a) where
4242
(<+>) = isoTrans
4343

44+
semigroupOpIsAssociative (MkIso ato afrom atoFrom afromTo)
45+
(MkIso bto bfrom btoFrom bfromTo)
46+
(MkIso cto cfrom ctoFrom cfromTo) =
47+
believe_me Iso
48+
4449
Monoid (Iso a a) where
4550
neutral = isoRefl
4651

52+
monoidNeutralIsNeutralL (MkIso to from toFrom fromTo) = believe_me Iso
53+
monoidNeutralIsNeutralR (MkIso to from toFrom fromTo) = believe_me Iso
54+
4755
||| Isomorphism is symmetric
4856
isoSym : Iso a b -> Iso b a
4957
isoSym (MkIso to from toFrom fromTo) = MkIso from to fromTo toFrom

libs/base/Control/Monad/Identity.idr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ Enum a => Enum (Identity a) where
3333
(Semigroup a) => Semigroup (Identity a) where
3434
(<+>) x y = Id (runIdentity x <+> runIdentity y)
3535

36+
semigroupOpIsAssociative (Id l) (Id c) (Id r) =
37+
rewrite semigroupOpIsAssociative l c r in Refl
38+
3639
(Monoid a) => Monoid (Identity a) where
37-
neutral = Id (neutral)
40+
neutral = Id (neutral)
41+
42+
monoidNeutralIsNeutralL (Id l) =
43+
rewrite monoidNeutralIsNeutralL l in Refl
44+
monoidNeutralIsNeutralR (Id r) =
45+
rewrite monoidNeutralIsNeutralR r in Refl

libs/base/Data/Morphisms.idr

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,28 @@ Monad (Morphism r) where
3131
Semigroup a => Semigroup (Morphism r a) where
3232
f <+> g = [| f <+> g |]
3333

34+
semigroupOpIsAssociative (Mor f) (Mor g) (Mor h) =
35+
cong {f = Mor} $ believe_me Morphism
36+
3437
Monoid a => Monoid (Morphism r a) where
3538
neutral = [| neutral |]
3639

40+
monoidNeutralIsNeutralL {r} {a} (Mor f) =
41+
cong {f = Mor} $ believe_me Morphism
42+
monoidNeutralIsNeutralR (Mor f) =
43+
cong {f = Mor} $ believe_me Morphism
44+
3745
Semigroup (Endomorphism a) where
3846
(Endo f) <+> (Endo g) = Endo $ g . f
3947

48+
semigroupOpIsAssociative (Endo _) (Endo _) (Endo _) = Refl
49+
4050
Monoid (Endomorphism a) where
4151
neutral = Endo id
4252

53+
monoidNeutralIsNeutralL (Endo _) = Refl
54+
monoidNeutralIsNeutralR (Endo _) = Refl
55+
4356
Functor f => Functor (Kleislimorphism f a) where
4457
map f (Kleisli g) = Kleisli (map f . g)
4558

@@ -51,12 +64,20 @@ Monad f => Monad (Kleislimorphism f a) where
5164
(Kleisli f) >>= g = Kleisli $ \r => applyKleisli (g !(f r)) r
5265

5366
-- Applicative is a bit too strong, but there is no suitable superclass
54-
(Semigroup a, Applicative f) => Semigroup (Kleislimorphism f r a) where
67+
(Semigroup a, Applicative f) => Semigroup (Kleislimorphism f s a) where
5568
f <+> g = [| f <+> g |]
5669

70+
semigroupOpIsAssociative (Kleisli i) (Kleisli j) (Kleisli k) =
71+
cong {f = Kleisli} $ believe_me Kleislimorphism
72+
5773
(Monoid a, Applicative f) => Monoid (Kleislimorphism f r a) where
5874
neutral = [| neutral |]
5975

76+
monoidNeutralIsNeutralL (Kleisli g) =
77+
cong {f = Kleisli} $ believe_me Kleislimorphism
78+
monoidNeutralIsNeutralR (Kleisli g) =
79+
cong {f = Kleisli} $ believe_me Kleislimorphism
80+
6081
Cast (Endomorphism a) (Morphism a a) where
6182
cast (Endo f) = Mor f
6283

libs/contrib/Control/Algebra.idr

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ infixl 7 <.>
1919
interface Monoid a => Group a where
2020
inverse : a -> a
2121

22+
groupInverseIsInverseR : (r : a) -> inverse r <+> r = Algebra.neutral
23+
2224
(<->) : Group a => a -> a -> a
2325
(<->) left right = left <+> (inverse right)
2426

@@ -36,7 +38,8 @@ interface Monoid a => Group a where
3638
||| + Inverse for `<+>`:
3739
||| forall a, a <+> inverse a == neutral
3840
||| forall a, inverse a <+> a == neutral
39-
interface Group a => AbelianGroup a where { }
41+
interface Group a => AbelianGroup a where
42+
abelianGroupOpIsCommutative : (l, r : a) -> l <+> r = r <+> l
4043

4144
||| Sets equipped with two binary operations, one associative and commutative
4245
||| supplied with a neutral element, and the other associative, with
@@ -61,6 +64,10 @@ interface Group a => AbelianGroup a where { }
6164
interface AbelianGroup a => Ring a where
6265
(<.>) : a -> a -> a
6366

67+
ringOpIsAssociative : (l, c, r : a) -> l <.> (c <.> r) = (l <.> c) <.> r
68+
ringOpIsDistributiveL : (l, c, r : a) -> l <.> (c <+> r) = (l <.> c) <+> (l <.> r)
69+
ringOpIsDistributiveR : (l, c, r : a) -> (l <+> c) <.> r = (l <.> r) <+> (c <.> r)
70+
6471
||| Sets equipped with two binary operations, one associative and commutative
6572
||| supplied with a neutral element, and the other associative supplied with a
6673
||| neutral element, with distributivity laws relating the two operations. Must
@@ -87,6 +94,34 @@ interface AbelianGroup a => Ring a where
8794
interface Ring a => RingWithUnity a where
8895
unity : a
8996

97+
ringWithUnityIsUnityL : (l : a) -> l <.> unity = l
98+
ringWithUnityIsUnityR : (r : a) -> unity <.> r = r
99+
100+
||| Sets equipped with two binary operations, one associative and
101+
||| commutative supplied with a neutral element, and the other
102+
||| associative and commutative, with distributivity laws relating the
103+
||| two operations. Must satisfy the following laws:
104+
|||
105+
||| + Associativity of `<+>`:
106+
||| forall a b c, a <+> (b <+> c) == (a <+> b) <+> c
107+
||| + Commutativity of `<+>`:
108+
||| forall a b, a <+> b == b <+> a
109+
||| + Neutral for `<+>`:
110+
||| forall a, a <+> neutral == a
111+
||| forall a, neutral <+> a == a
112+
||| + Inverse for `<+>`:
113+
||| forall a, a <+> inverse a == neutral
114+
||| forall a, inverse a <+> a == neutral
115+
||| + Associativity of `<.>`:
116+
||| forall a b c, a <.> (b <.> c) == (a <.> b) <.> c
117+
||| + Commutativity of `<.>`:
118+
||| forall a b, a <.> b == b <.> a
119+
||| + Distributivity of `<.>` and `<+>`:
120+
||| forall a b c, a <.> (b <+> c) == (a <.> b) <+> (a <.> c)
121+
||| forall a b c, (a <+> b) <.> c == (a <.> c) <+> (b <.> c)
122+
interface Ring a => CommutativeRing a where
123+
ringOpIsCommutative : (x, y : a) -> x <.> y = y <.> x
124+
90125
||| Sets equipped with two binary operations – both associative, commutative and
91126
||| possessing a neutral element – and distributivity laws relating the two
92127
||| operations. All elements except the additive identity must have a
@@ -104,6 +139,8 @@ interface Ring a => RingWithUnity a where
104139
||| forall a, inverse a <+> a == neutral
105140
||| + Associativity of `<.>`:
106141
||| forall a b c, a <.> (b <.> c) == (a <.> b) <.> c
142+
||| + Commutativity of `<.>`:
143+
||| forall a b, a <.> b == b <.> a
107144
||| + Unity for `<.>`:
108145
||| forall a, a <.> unity == a
109146
||| forall a, unity <.> a == a
@@ -113,9 +150,12 @@ interface Ring a => RingWithUnity a where
113150
||| + Distributivity of `<.>` and `<+>`:
114151
||| forall a b c, a <.> (b <+> c) == (a <.> b) <+> (a <.> c)
115152
||| forall a b c, (a <+> b) <.> c == (a <.> c) <+> (b <.> c)
116-
interface RingWithUnity a => Field a where
153+
interface (RingWithUnity a, CommutativeRing a) => Field a where
117154
inverseM : (x : a) -> Not (x = Algebra.neutral) -> a
118155

156+
fieldInverseIsInverseR : (r : a) -> (p : Not (r = Algebra.neutral)) ->
157+
inverseM r p <.> r = Algebra.unity
158+
119159
sum' : (Foldable t, Monoid a) => t a -> a
120160
sum' = concat
121161

@@ -145,3 +185,33 @@ mtimes (S k) x = stimes (S k) x
145185
-- Structures where "abs" make sense.
146186
-- Euclidean domains, etc.
147187
-- Where to put fromInteger and fromRational?
188+
189+
-- Unverified implementations ----------
190+
191+
infixl 7 <?+>
192+
infixl 8 <?.>
193+
194+
interface UnverifiedSemigroup a where
195+
(<?+>) : a -> a -> a
196+
197+
interface UnverifiedSemigroup a => UnverifiedMonoid a where
198+
neut : a
199+
200+
interface UnverifiedMonoid a => UnverifiedGroup a where
201+
inv : a -> a
202+
203+
interface UnverifiedGroup a => UnverifiedAbelianGroup a where { }
204+
205+
interface UnverifiedAbelianGroup a => UnverifiedRing a where
206+
(<?.>) : a -> a -> a
207+
208+
interface UnverifiedRing a => UnverifiedRingWithUnity a where
209+
un : a
210+
211+
interface UnverifiedRingWithUnity a => UnverifiedField a where
212+
inverse_M : (x : a) -> Not (x = Algebra.neut) -> a
213+
214+
-- Lattices
215+
216+
interface UnverifiedJoinSemilattice a where
217+
join : a -> a -> a

libs/contrib/Control/Algebra/Lattice.idr

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Control.Algebra.Lattice
22

33
import Control.Algebra
4-
import Data.Heap
4+
import Data.Bool.Extra
55

66
%access public export
77

@@ -19,14 +19,9 @@ import Data.Heap
1919
interface JoinSemilattice a where
2020
join : a -> a -> a
2121

22-
implementation JoinSemilattice Nat where
23-
join = maximum
24-
25-
implementation Ord a => JoinSemilattice (MaxiphobicHeap a) where
26-
join = merge
27-
28-
JoinSemilattice Bool where
29-
join a b = a || b
22+
joinSemilatticeJoinIsAssociative : (l, c, r : a) -> join l (join c r) = join (join l c) r
23+
joinSemilatticeJoinIsCommutative : (l, r : a) -> join l r = join r l
24+
joinSemilatticeJoinIsIdempotent : (e : a) -> join e e = e
3025

3126
||| Sets equipped with a binary operation that is commutative, associative and
3227
||| idempotent. Must satisfy the following laws:
@@ -42,11 +37,9 @@ JoinSemilattice Bool where
4237
interface MeetSemilattice a where
4338
meet : a -> a -> a
4439

45-
implementation MeetSemilattice Nat where
46-
meet = minimum
47-
48-
MeetSemilattice Bool where
49-
meet a b = a && b
40+
meetSemilatticeMeetIsAssociative : (l, c, r : a) -> meet l (meet c r) = meet (meet l c) r
41+
meetSemilatticeMeetIsCommutative : (l, r : a) -> meet l r = meet r l
42+
meetSemilatticeMeetIsIdempotent : (e : a) -> meet e e = e
5043

5144
||| Sets equipped with a binary operation that is commutative, associative and
5245
||| idempotent and supplied with a unitary element. Must satisfy the following
@@ -66,11 +59,7 @@ MeetSemilattice Bool where
6659
interface JoinSemilattice a => BoundedJoinSemilattice a where
6760
bottom : a
6861

69-
implementation BoundedJoinSemilattice Nat where
70-
bottom = Z
71-
72-
BoundedJoinSemilattice Bool where
73-
bottom = False
62+
joinBottomIsIdentity : (x : a) -> join x Lattice.bottom = x
7463

7564
||| Sets equipped with a binary operation that is commutative, associative and
7665
||| idempotent and supplied with a unitary element. Must satisfy the following
@@ -90,8 +79,7 @@ BoundedJoinSemilattice Bool where
9079
interface MeetSemilattice a => BoundedMeetSemilattice a where
9180
top : a
9281

93-
BoundedMeetSemilattice Bool where
94-
top = True
82+
meetTopIsIdentity : (x : a) -> meet x Lattice.top = x
9583

9684
||| Sets equipped with two binary operations that are both commutative,
9785
||| associative and idempotent, along with absorbtion laws for relating the two
@@ -109,11 +97,7 @@ BoundedMeetSemilattice Bool where
10997
||| + Absorbtion laws for meet and join:
11098
||| forall a b, meet a (join a b) == a
11199
||| forall a b, join a (meet a b) == a
112-
interface (JoinSemilattice a, MeetSemilattice a) => Lattice a where { }
113-
114-
implementation Lattice Nat where { }
115-
116-
Lattice Bool where { }
100+
interface (JoinSemilattice a, MeetSemilattice a) => UnverifiedLattice a where { }
117101

118102
||| Sets equipped with two binary operations that are both commutative,
119103
||| associative and idempotent and supplied with neutral elements, along with
@@ -135,6 +119,52 @@ Lattice Bool where { }
135119
||| + Neutral for meet and join:
136120
||| forall a, meet a top == top
137121
||| forall a, join a bottom == bottom
138-
interface (BoundedJoinSemilattice a, BoundedMeetSemilattice a) => BoundedLattice a where { }
122+
interface (BoundedJoinSemilattice a, BoundedMeetSemilattice a) => UnverifiedBoundedLattice a where { }
123+
124+
-- Implementations ---------------------
125+
126+
-- Nat
127+
128+
JoinSemilattice Nat where
129+
join = maximum
130+
joinSemilatticeJoinIsAssociative = maximumAssociative
131+
joinSemilatticeJoinIsCommutative = maximumCommutative
132+
joinSemilatticeJoinIsIdempotent = maximumIdempotent
133+
134+
MeetSemilattice Nat where
135+
meet = minimum
136+
meetSemilatticeMeetIsAssociative = minimumAssociative
137+
meetSemilatticeMeetIsCommutative = minimumCommutative
138+
meetSemilatticeMeetIsIdempotent = minimumIdempotent
139+
140+
BoundedJoinSemilattice Nat where
141+
bottom = Z
142+
joinBottomIsIdentity = maximumZeroNLeft
143+
144+
UnverifiedLattice Nat where { }
145+
146+
-- Bool
147+
148+
JoinSemilattice Bool where
149+
join a b = a || b
150+
joinSemilatticeJoinIsAssociative = orAssociative
151+
joinSemilatticeJoinIsCommutative = orCommutative
152+
joinSemilatticeJoinIsIdempotent = orSameNeutral
153+
154+
MeetSemilattice Bool where
155+
meet a b = a && b
156+
meetSemilatticeMeetIsAssociative = andAssociative
157+
meetSemilatticeMeetIsCommutative = andCommutative
158+
meetSemilatticeMeetIsIdempotent = andSameNeutral
159+
160+
BoundedJoinSemilattice Bool where
161+
bottom = False
162+
joinBottomIsIdentity = orFalseNeutral
163+
164+
BoundedMeetSemilattice Bool where
165+
top = True
166+
meetTopIsIdentity = andTrueNeutral
167+
168+
UnverifiedBoundedLattice Bool where { }
139169

140-
BoundedLattice Bool where { }
170+
UnverifiedLattice Bool where { }

0 commit comments

Comments
 (0)