Search code examples
coqssreflect

Simplifying expression with lists equality


My task is to implement an instance of equality type for the seq datatype. To do this I need to create a comparison function and a proof that this function is correct:

From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat div seq.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Fixpoint eq_seq {T: eqType} (x y: seq T) : bool :=
  match x, y with
  | [::],[::] => true
  | cons x' xs, [::] => false
  | [::], cons y' ys => false
  | cons x' xs, cons y' ys => (x' == y') && eq_seq xs ys
  end.

Arguments eq_seq T x y : simpl nomatch.

Lemma eq_seq_correct : forall T: eqType, Equality.axiom (@eq_seq T).
Proof.
  move=> T x. elim: x=> [|x' xs].
  - move=> y. case: y=> //=; by constructor.
  - move=> IH y. case: y=> [| y' ys].
    + rewrite /(eq_seq (x' :: xs) [::]). constructor. done.
    + move=> /=. case E: (x' == y').
      * move: E. case: eqP=> E _ //=. rewrite <- E.

Result:

2 subgoals (ID 290)

  T : eqType
  x' : T
  xs : seq T
  IH : forall y : seq T, reflect (xs = y) (eq_seq xs y)
  y' : T
  ys : seq T
  E : x' = y'
  ============================
  reflect (x' :: xs = x' :: ys) (eq_seq xs ys)

subgoal 2 (ID 199) is:
 reflect (x' :: xs = y' :: ys) (false && eq_seq xs ys)

How to get rid of x' in both sides of equality: (x' :: xs = x' :: ys)?

I tried case: (x' :: xs = x' :: ys), but it didn't help.


Solution

  • (Just in case you are not aware, this lemma is already proved in the seq library. Look for eqseqP.)

    The key step in completing the proof is the iffP lemma:

    iffP : forall P Q b, reflect P b -> (P -> Q) -> (Q -> P) -> reflect Q b.
    

    Thus, by calling apply/(iffP (IH ys)), we reduce the current goal to proving that xs = ys -> x' :: xs = x' :: ys and x' :: xs = x' :: ys -> xs = ys. You can discharge both subgoals by applying the congruence tactic.