Search code examples
proofdependent-typeidristheorem-provingformal-verification

Rewriting in simple theorem proof


I wrote a definition of group in Idris:

data Group: Type -> Type where
    Unit: (x: t) -> Group t
    (*): Group t -> Group t -> Group t
    Inv: Group t -> Group t
postulate
    assoc: (a : Group t) -> (b : Group t) -> (c : Group t) -> ((a*b)*c = a*(b*c))
postulate
    neutralL: (x: t) -> (a : Group t) -> a * Unit x = a
postulate
    neutralR: (x: t) -> (a : Group t) -> Unit x * a = a
postulate
    invUnitL: (x: t) -> (a : Group t) -> a * (Inv a) = Unit x
postulate
    invUnitR: (x: t) -> (a : Group t) -> (Inv a) * a = Unit x

Then I proved a couple of simple propositions:

cong : (a : Group t) -> (b : Group t) -> (c: Group t) -> a = b -> a*c = b*c
cong a b c post = rewrite post in Refl

neutralL1: (x: t) -> (a : Group t) -> a = a * Unit x
neutralL1 x a = rewrite neutralL x a in Refl

neutralR1: (x: t) -> (a : Group t) -> a = Unit x * a
neutralR1 x a = rewrite neutralR x a in Refl

However, I have a problem with proving that there is only one unit element:

singleUnit : (x: t) -> (y: t) -> (Unit x = Unit y)

I tried various expressions using a general idea, that Unit x = (by neutralL1 y (Unit x)) = Unit x * Unit y = (by neutralR x (Unit y)) = Unit y, but with no success:

singleUnit x y = rewrite neutralL1 y (Unit x) in neutralR x (Unit y)
singleUnit x y = rewrite neutralL1 y (Unit x) in rewrite neutralR x (Unit y) in Refl
singleUnit x y = rewrite neutralR x (Unit y) in neutralL1 y (Unit x)
singleUnit x y = rewrite neutralR x (Unit y) in rewrite neutralL1 y (Unit x) in Refl

How can I prove this? I have a feeling, that the problem here is related to substitution of complex expressions, like Unit x * Unit y.


Solution

  • Unfortunately, this definition of a group won't work. In general, you have to be very careful introducing new axioms (postulates).

    E.g. it's easy to see that neutralL violates the principle of disjointness of (different) data constructors, i.e. Constr1 <data> != Constr2 <data>.

    starAndUnitAreDisjoint : (*) a (Unit x) = a -> Void
    starAndUnitAreDisjoint Refl impossible
    

    Now we can prove false:

    contradiction : Void
    contradiction = starAndUnitAreDisjoint $ neutralL Z (Unit Z)
    

    Finita la commedia!

    What you actually want is a record or a typeclass, see e.g. contrib/Control/Algebra.idr and contrib/Interfaces/Verified.idr. In addition, Agda versions are syntactically pretty close to Idris (agda-stdlib/src/Algebra.agda and probably the Abstract Algebra in Agda tutorial) -- you might want to have a look at them.