Proving forall x xs ys, subseq (x :: xs) ys -> subseq xs ys in Coq
Question
I have the following definition
Inductive subseq : list nat -> list nat -> Prop :=
| empty_subseq : subseq [] []
| add_right : forall y xs ys, subseq xs ys -> subseq xs (y :: ys)
| add_both : forall x y xs ys, subseq xs ys -> subseq (x :: xs) (y :: ys).
Using this, I wish to prove the following lemma
forall (x : nat) (xs ys : list nat),
subseq (x :: xs) ys -> subseq xs ys
So, I tried looking at the proof of subseq (x :: xs) ys by doing destruct H.
forall (x : nat) (xs ys : list nat), subseq (x :: xs) ys -> subseq xs ysx: nat
xs, ys: list nat
H: subseq (x :: xs) yssubseq xs ysx: nat
xs: list natsubseq xs []x: nat
xs: list nat
y: nat
xs0, ys: list nat
H: subseq xs0 ys
IHsubseq: subseq xs yssubseq xs (y :: ys)x: nat
xs: list nat
x0, y: nat
xs0, ys: list nat
H: subseq xs0 ys
IHsubseq: subseq xs yssubseq xs (y :: ys)
Why does the first subgoal ask me to prove subseq xs []? Shouldn't the destruct tactic know that the proof cannot be of the form empty_subseq since the type contains x :: xs and not []?
In general how do I prove the lemma that I am trying to prove?
Answer (Li-yao Xia)
Shouldn't the destruct tactic know that the proof cannot be of the form empty_subseq since the type contains x :: xs and not []?
In fact, destruct doesn't know that much. It just replaces x :: xs and xs with [] and [] in the empty_subseq case. In particular, this frequently leads to lost information in the context. Better alternatives:
Use inversion instead of destruct.
Use remember to ensure both type indices of subseq are variables before destruct. (remember (x :: xs) as xxs in H.) This more explicit goal management also works well with induction.
Answer (Agnishom Chattopadhyay)
Li-yao's answer was actually useful. This is a proof of the lemma.
forall (x : nat) (xs ys : list nat), subseq (x :: xs) ys -> subseq xs ysforall (x : nat) (xs ys : list nat), subseq (x :: xs) ys -> subseq xs ysx: nat
xs, ys: list natsubseq (x :: xs) ys -> subseq xs ysx: nat
xs: list natsubseq (x :: xs) [] -> subseq xs []x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'subseq (x :: xs) (y :: ys') -> subseq xs (y :: ys')x: nat
xs: list natsubseq (x :: xs) [] -> subseq xs []inversion H. (* Inversion will detect that no constructor matches the type of H *)x: nat
xs: list nat
H: subseq (x :: xs) []subseq xs []x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'subseq (x :: xs) (y :: ys') -> subseq xs (y :: ys')x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')subseq xs (y :: ys')(* Inversion will automatically discharge the first case *)x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')
y0: nat
xs0, ys: list nat
H2: subseq (x :: xs) ys'
H1: xs0 = x :: xs
H0: y0 = y
H3: ys = ys'subseq xs (y :: ys')x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')
x0, y0: nat
xs0, ys: list nat
H1: subseq xs ys'
H0: x0 = x
H2: xs0 = xs
H3: y0 = y
H4: ys = ys'subseq xs (y :: ys')x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')
y0: nat
xs0, ys: list nat
H2: subseq (x :: xs) ys'
H1: xs0 = x :: xs
H0: y0 = y
H3: ys = ys'subseq xs (y :: ys')now apply add_right.x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')
y0: nat
xs0, ys: list nat
H2: subseq xs ys'
H1: xs0 = x :: xs
H0: y0 = y
H3: ys = ys'subseq xs (y :: ys')now apply add_right. Qed.x: nat
xs: list nat
y: nat
ys': list nat
IHys': subseq (x :: xs) ys' -> subseq xs ys'
H: subseq (x :: xs) (y :: ys')
x0, y0: nat
xs0, ys: list nat
H1: subseq xs ys'
H0: x0 = x
H2: xs0 = xs
H3: y0 = y
H4: ys = ys'subseq xs (y :: ys')