Equality testing without explicit proof that data constructors are injective - equality

Is it possible to define a simple syntactic notion of equality (similar to what GHC might automatically derive as the Eq instance for a Haskell 98 type), without either explicitly proving that each data constructor is injective, or doing something analogous, such as defining the retraction of each constructor and using cong?
In other words, is it possible to exploit the injectivity of data constructors more directly, rather than having to introduce one auxiliary function per constructor?
The following uses the natural numbers as an example.
module Eq where
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
data ℕ : Set where
zero : ℕ
suc : ℕ → ℕ
-- How to eliminate these injectivity proofs?
suc-injective : ∀ {n m} → suc n ≡ suc m → n ≡ m
suc-injective refl = refl
_≟_ : Decidable {A = ℕ} _≡_
zero ≟ suc _ = no (λ ())
suc _ ≟ zero = no (λ ())
zero ≟ zero = yes refl
suc n ≟ suc m with n ≟ m
suc n ≟ suc .n | yes refl = yes refl
... | no n≢m = no (n≢m ∘ suc-injective)
One could replace suc-injective by cong (λ { zero → zero ; (suc x) → x }), i.e. by defining a function which inverts suc, but that still requires boilerplate of one auxiliary function per constructor, and such functions are somewhat ugly to define because of the need to be total.
(Usual caveats re. missing something obvious apply.)

Ulf Norell's prelude for Agda contains a mechanism for automatically deriving decidable equality for a given datatype. The code is based on Agda's reflection mechanism and automatically generated extended lambdas for proving injectivity of constructors. I recommend taking a look at the code, even though it's not always as simple as it could be.

Related

Idris Dependent Pairs: Unexpected behavior between compiled program and REPL

When practicing using dependent pairs in Idris, I have encountered an unexpected difference in behavior between compiled programs and the REPL. The following datatype is what I am testing with:
(a : Type ** b : Type ** Arrow a b)
Which should represent some relation between type a and type b. Given an instance of the above, I would like to extract the "proof" term of the type. I can do this from the REPL with DPair.snd $ DPair.snd <some-instance> and everything works fine. However, if I try to make a function:
unwrap : (a ** b ** Arrow a b) -> Arrow a b
unwrap x = DPair.snd $ DPair.snd x
the program will compile, but will fail when I try to call it. The error message returned is
(input): No such variable b
Has anyone encountered this or knows of a solution?
What you want to achieve is not possible. If you look at the type of unwrap : (a1 : Type ** b1 : Type ** Arrow a b) -> Arrow a b you see that it uses a different datatype than (a : Type ** b : Type ** Arrow a b). That's because the arguments a, b are quantified beforehand - setting the resulting type (which is also the difference to the REPL case; there you aren't bound to the arguments). So with :set showimplicit it is
Main.unwrap : {b : Type} -> {a : Type} ->
(a1 : Type ** b1 : Type ** Main.Arrow a b) ->
Main.Arrow a b
That's the thing about dependent pairs, you can't restrict them easily. Take a look at Vect.filter : (elem -> Bool) -> Vect len elem -> (p : Nat ** Vect p elem) - if we had a function like unwrap : (p : Nat ** Vect p elem) -> Vect p elem, we wouldn't need dependent pair in the first place.
Instead, a function that would call unwrap would need to inspect p and then handle the Vect accordingly. Sadly, we can't easily inspect types (at least if you want to generalize for all types). So your best bet is: don't use dependent types here.
I realise I'm a year and a half late, but... This absolutely is possible! You just need to remember that the type a ** P is just syntactic sugar for DPair a (\x => P a); in the latter form, nothing special is going on whatsoever and so you can use your a and b just like you'd expect. We can also gain insight from how DPair.snd is typed in the standard library:
Idris> :t DPair.snd
snd : (x : DPair a P) -> P (fst x)
So, to extract the a-value from our pair, we simply call fst on that pair. How intuitive! (fst itself simply has the type DPair a P -> a). To get the b-value, which is the first value of the second part of our pair, we call fst . snd on the outermost pair. Therefore, your function should look like:
unwrap : (x : DPair a (DPair b . Arrow)) -> Arrow (fst x) (snd $ fst x)
unwrap x = snd (snd x)
(or, equivalently:)
unwrap : (x : DPair a (\theA => DPair b (\theB => Arrow theA theB))) -> ...
For whatever reason, unwrap = DPair.snd . DPair.snd doesn't work... but that's not too much of an issue.

In Lean, is it possible to use decidable_linear_order with a user defined equality relation?

Lean comes with a decidable_linear_order typeclass containing useful lemmas about an ordering and its relation to equality, such as:
lemma eq_or_lt_of_not_lt [decidable_linear_order α] {a b : α} (h : ¬ a < b) : a = b ∨ b < a
The equalities in these orderings are all expressed in terms of =:
inductive eq {α : Sort u} (a : α) : α → Prop
| refl : eq a
I was wondering whether it would be possible to somehow extend this class (and its superclasses) to work with an arbitrary used defined equality relation R: α → α → Prop that was reflexive, symmetric and transitive, or would this only be possible by rewriting all the relevant lemmas and their proofs to use R instead of eq?
Since these classes are not parameterized by the equality relation, you would indeed have to reimplement them (perhaps metaprogramming may be of help for that). Alternatively, because you have an equivalence relation, you could define your order on the quotient type and so keep using eq.

Why is this mutually recursive data definition not total and how can I fix it?

I am experimenting with Idris a lot lately and came up with the following "type level definition of a set":
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> Not (Elem x xs) -> Set a
data Elem : (x : a) -> Set a -> Type where
Here : Elem x (Insert x xs p)
There : Elem x xs -> Elem x (Insert y xs p)
So a set is either empty or it consists of a set and an additional element that is proven not to be in that set already.
When I totality check this, I get the error
[...] is not strictly positive
for Insert, Here and There. I have been searching the documentation for terms like "strictly positive" and the totality checker in general, but I cannot figure out why this case in particular is not total (or strictly positive). Can somebody explain this?
The natural next question then is of course how to "fix" it. Can I somehow change the definition, keeping its semantics, so that it totality checks?
Since I don't really need the definition to look like this (it is only an experiment after all) it would also be interesting to know whether there is another, somehow more idiomatic way to represent Sets at the type level that is total.
This SO post explains what strictly positive types are and why they matter. In your case, since Not (Elem x xs) simply means a function Elem x xs -> Void, this is where the "type being defined occurring on the left-hand side of an arrow" comes from.
Can you make do with something like this?
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> NotElem x xs -> Set a
data NotElem : (x : a) -> Set a -> Type where
NotInEmpty : NotElem x Empty
NotInInsert : Not (x = y) -> NotElem x ys -> NotElem x (Insert y ys p)

Decidability of propositional equaility

Two terms in agda are said to be definitionally equal precisely when they both have the same normal form ---I think---, and propositional equality is just the data-type representation of definitional equality ---again, I guess---; so then shouldn't propositionally equality be decidable? That is, would it seem reasonable that we can write a function typed
∀{A : Set} → (x y : A) → Dec(x ≡ y).
I kinda of get that we cannot write such a function since we cannot pattern match on the arguments, but I 'feel' that it should be possible: again, just reduce to normal form and check for syntactic identity.
Any insight would be helpful!
Two terms in agda are said to be definitionally equal precisely when
they both have the same normal form
Up to αη-conversion.
and propositional equality is just the data-type representation of definitional equality
Propositional equality says "these two terms will become definitionally equal after you instantiate some free variables" ("some" can be 0 or all of them) ("instantiate" can vary too).
E.g.
double-double : (n : ℕ) -> n + n ≡ 2 * n
clearly, n + n is not syntactically equal to 2 * n, but for any canonical n (0, 1, 2...) the result of n + n is syntactically equal to the result of 2 * n — that's what double-double says. And that "for any canonical n" part forces us to prove double-double by induction (though, in a more complicated system, where definitional equality is based on supercompilation or there is a build-in prover, n + n is definitionally equal to 2 * n).
But sometimes it's not as obvious how an induction hypothesis should look like, e.g. when you need to generalize an equation. As you might expect, there is no decision procedure for "is this arbitrary thing provable?" and hence propositional equality is undecidable. Moreover, you can't neither prove nor disprove statements like
(λ n -> 1 + n) ≡ (λ n -> n + 1)
without additional postulates.
However you really can check for syntactic equality:
_≟_ : ∀ {α} {A : Set α} -> (x y : A) -> Maybe (x ≡ y)
It says "if two terms are syntactically equal, then they are equal propositionally, otherwise we don't know whether they are equal propositionally or not". But Agda doesn't have such built-in function.

How or is that possible to prove or falsify `forall (P Q : Prop), (P -> Q) -> (Q -> P) -> P = Q.` in Coq?

I want to prove or falsify forall (P Q : Prop), (P -> Q) -> (Q -> P) -> P = Q. in Coq. Here is my approach.
Inductive True2 : Prop :=
| One : True2
| Two : True2.
Lemma True_has_one : forall (t0 t1 : True), t0 = t1.
Proof.
intros.
destruct t0. destruct t1.
reflexivity.
Qed.
Lemma not_True2_has_one : (forall (t0 t1 : True2), t0 = t1) -> False.
Proof.
intros.
specialize (H One Two).
inversion H.
But, inversion H does nothing. I think maybe it's because the coq's proof independence (I'm not a native English speaker, and I don't know the exact words, please forgive my ignorance), and coq makes it impossible to prove One = Two -> False. But if so why has to coq eliminate the content of a proof?
Without the above proposition, I can't prove the followings or their negations.
Lemma True_neq_True2 : True = True2 -> False.
Theorem iff_eq : forall (P Q : Prop), (P -> Q) -> (Q -> P) -> P = Q.
So my question is:
How to or is that possible to prove or falsify forall (P Q : Prop),
(P -> Q) -> (Q -> P) -> P = Q. in Coq?
Why inversion H does nothing; does it's because the coq's proof independence, and if so, why does Coq waste energy in doing this.
The principle you're mentioning, forall P Q : Prop, (P <-> Q) -> P = Q, is usually known as propositional extensionality. This principle is not provable in Coq's logic, and originally the logic had been designed so that it could be added as an axiom with no harm. Thus, in the standard library (Coq.Logic.ClassicalFacts), one can find many theorems about this principle, relating it to other well-known logical principles of classical reasoning. Surprisingly, it was recently found out that Coq's logic is incompatible with this principle, but for a very subtle reason. This is considered a bug, since the logic had been designed so that this could be added as an axiom with no harm. They wanted to fix this problem in the new version of Coq, but I don't know what the current status of that is. As of version 8.4, propositional extensionality is inconsistent in Coq.
In any case, if this bug is fixed in future versions of Coq, it should not be possible to prove nor disprove this principle in Coq. In other words, the Coq team wants this principle to be independent of Coq's logic.
inversion H doesn't do anything there because the rules for reasoning about proofs (things whose type is a Prop) are different from the ones for reasoning about non-proofs (things whose type is a Type). You may know that proofs in Coq are just terms. Under the hood, inversion is essentially constructing the following term:
Definition true_not_false : true <> false :=
fun H =>
match H in _ = b
return if b then True else False
with
| eq_refl => I
end.
If you try to do the same with a version of bool in Prop, you get a more informative error:
Inductive Pbool : Prop :=
| Ptrue : Pbool
| Pfalse : Pbool.
Fail Definition Ptrue_not_Pfalse : Ptrue <> Pfalse :=
fun H =>
match H in _ = b
return if b then True else False
with
| eq_refl => I
end.
(* The command has indeed failed with message: *)
(* => Error: *)
(* Incorrect elimination of "b" in the inductive type "Pbool": *)
(* the return type has sort "Type" while it should be "Prop". *)
(* Elimination of an inductive object of sort Prop *)
(* is not allowed on a predicate in sort Type *)
(* because proofs can be eliminated only to build proofs. *)
Indeed, one of the reasons for this is that Coq was designed to be compatible with another principle called proof irrelevance (I think that's what you meant by "proof independence").