0

The authors of the book have provided proofs for some unit tests for nostutter exercise. Unfortunately, they didn't provide explanations how they work. I was able to understand all the proofs but one:

Inductive nostutter {X:Type} : list X -> Prop :=
| ns_nil : nostutter []
| ns_one : forall (x : X), nostutter [x]
| ns_cons: forall (x : X) (h : X) (t : list X), nostutter (h::t) -> x <> h -> nostutter (x::h::t).

Example test_nostutter_4:      not (nostutter [3;1;1;4]).
Proof.
  intro.
  repeat match goal with
    h: nostutter _ |- _ => inversion h; clear h; subst
         end.
  contradiction.
Qed.

After intro we have the following:

1 subgoal (ID 454)

H : nostutter [3; 1; 1; 4]
============================
False

When I remove repeat and run match once, I get this:

1 subgoal (ID 519)

H2 : nostutter [1; 1; 4]
H4 : 3 <> 1
============================
False

So it tries to recursively find, where the list in H2 doesn't match any of nostutter constructors.

Can somebody explain me, how does this match work step by step? What is goal variable and |- symbol?

user4035
  • 22,508
  • 11
  • 59
  • 94

1 Answers1

2

Let me first prove this in hard way.

Example test_nostutter_4:      not (nostutter [3;1;1;4]).
Proof.
  intro.
  (* You can think of this inversion H as 
     destructing nostutter [3; 1; 1; 4] into 
     ns_cons 3 1 [1; 4] (Trm : nostutter [1 :: 1 :: 4]) (Prf : 3 <> 1) *)
  inversion H.
  (* Let's invert Trm again. The process is same and I am leaving it for you to figure out*)
  inversion H2.
  (* At this point, you can easily that H9 say that 1 <> 1 which is off-course a false 
     assumption*)
  unfold not in H9.
  specialize (H9 eq_refl).
  Print False. (* False is inductive data type with no constructor*)
  inversion H9.
Qed.

As you can see that my proof has a lot of repetition, and we can easily automate them. Coq has tactic language called Ltac to combine tactics [1]. In your proof, the goal is

1 subgoal (ID 454)

H : nostutter [3; 1; 1; 4]
============================
False

and "match goal with" is pattern matching on goal. Everything at top of line (======) is assumption and below is the thing we need to prove. Rather than using line (======) to separate assumption with goal, Ltac uses turnstile (Assumption |- Goal [2]). I hope I am clear enough, but let me know if something is not clear.

[1] https://coq.inria.fr/refman/proof-engine/ltac.html#coq:tacn.match-goal

[2] https://en.wikipedia.org/wiki/Turnstile_(symbol)

keep_learning
  • 1,057
  • 5
  • 14
  • Can you give a simple example of `match goal with` construction, explaining how it works? – user4035 Jun 26 '19 at 14:23
  • As far as I understand: "h: nostutter _ |- _ =>" means: if one of hypothesis matches constructor `nostutter something` and goal matches something do the actions after `=>`. Correct? Why do they check only nostutter constructor with 1 argument, while we need a constructor with 3 arguments? – user4035 Jun 26 '19 at 14:26
  • @user4035 You are almost right in first observation except nonstutter in not a constructor (constructor nostutter something), but it's family of types which takes list X to return a Prop. They are checking on term of type nonstutter _ . "h: nostutter _ |- _ =>" matches a hypothesis h : nostutter _ or term h of type nostutter _ and it does not care what is on the right hand side of turnstile. Once it has found a match then it invert the term h, followed by clearing from context and substituting all values "inversion h; clear h; subst" . – keep_learning Jun 26 '19 at 23:29
  • What do `Trm` and `Prf` shortcuts stand for? – user4035 Jun 27 '19 at 14:45
  • @user4035 Basically, they are just variables like H0, H1, x but I named it Trm and Prf for make it explicit about term and proof, but you can safely ignore it. – keep_learning Jun 28 '19 at 04:54