Index

Table of Contents

1 Useful user-defined tactics** The Case tactic

Taken from Pierce's Software Foundation, it can be used to document a proof by annotating the proof context with the ongoing case.

Require String. Open Scope string_scope.

Ltac move_to_top x :=
match reverse goal with
| H : _ | - _ => try move x after H |
end.

Tactic Notation "assert_eq" ident(x) constr(v) :=
let H := fresh in
assert (x = v) as H by reflexivity;
clear H.

Tactic Notation "Case_aux" ident(x) constr(name) :=
first [
set (x := name); move_to_top x
| assert_eq x name; move_to_top x
| fail 1 "because we are working on a different case" ].

Tactic Notation "Case" constr(name) := Case_aux Case name.
Tactic Notation "SCase" constr(name) := Case_aux SCase name.
Tactic Notation "SSCase" constr(name) := Case_aux SSCase name.
Tactic Notation "SSSCase" constr(name) := Case_aux SSSCase name.
Tactic Notation "SSSSCase" constr(name) := Case_aux SSSSCase name.
Tactic Notation "SSSSSCase" constr(name) := Case_aux SSSSSCase name.
Tactic Notation "SSSSSSCase" constr(name) := Case_aux SSSSSSCase name.
Tactic Notation "SSSSSSSCase" constr(name) := Case_aux SSSSSSSCase name.

I often need to perform case analysis on the discriminee of a match construct. To do so, use the following tactic:

Ltac destr :=
  match goal with
   |- context [ match ?e with _ => _ end ] => destruct e eqn:?
  end.

From this you can build your own variant of the tactic that runs arbitrary tactics after destructing, for instance simplifying or trying to eliminate simpl goals. My variant simplifies in the whole context and tries to solve goals using intuition congruence.

Ltac destr' := repeat destr; simpl in *; try intuition congruence.

2 Automation facilities

2.1 Using tactics like reflexivity over user built relations

The goal here is to be able to use coq's built-in tactics over other relations than iff and eq, in particular relations that you have defined yourself.

2.1.1 Adding equivalence relations, preorder, etc…

The inner mechanism going on when using tactics like reflexivity, transitivity or symmetry is typeclasses. However coq allows a particular facility to declare new relation without digging into this. The syntax goes roughly as follows:

Add Parametric Relation (A: Type): A (@R A)
reflexivity proved by ...
symmetry proved by ...
transitivity proved by ...
as R_is_an_equivalence_relation.

Note that you naturally only want to take A as a parameter if your relation is indeed polymorphic. For instance, suppose you need to manipulate predicates over program states up to propositional extentional equivalence. This relation is an equivalence relation, so you might want to declare it as so.

Axiom state: Type.
Definition Pred: state -> Prop.
Definition PEq (P1 P2: Pred): Prop := forall x, P1 x <-> P2 x.
Lemma PEq_reflexive: forall P, P ≡ P.
Proof.
  intros P s; go.
Qed.

Lemma PEq_trans: forall P1 P2 P3 (H1: P1 ≡ P2) (H2: P2 ≡ P3),
    P1 ≡ P3.
  intros P1 P2 P3 H1 H2 s; split; intros H3; [apply H2, H1 | apply H1,H2]; assumption.
Qed.

Lemma PEq_symm: forall P1 P2 (H: P1 ≡ P2), P2 ≡ P1.
Proof.
  intros P1 P2 H s; split; intros H'; apply H; assumption.
Qed.

Add Parametric Relation: Pred PEq
    reflexivity proved by PEq_reflexive
    symmetry proved by PEq_symm
    transitivity proved by PEq_trans
      as PEq_equiv.

We now are able to prove goals such that (forall P: Pred, PEq P P) with a simpl (intros P; reflexivity). Same goes for transitivity and symmetry.

Note that we can also only declare some of those properties, declaring that a relation is a preorder for instance:

Definition PWeaker (P1 P2: Pred): Prop := forall s, P2 s -> P1 s.

Lemma PWeaker_reflexive: forall P, P ⊆ P.
Proof.
  go.
Qed.

Lemma PWeaker_trans: forall P1 P2 P3 (H1: P1 ⊆ P2) (H2: P2 ⊆ P3), P1 ⊆ P3.
Proof.
  intros P1 P2 P3 H1 H2 s H3; apply H1,H2,H3.
Qed.

Add Parametric Relation: Pred PWeaker
    reflexivity proved by PWeaker_reflexive
    transitivity proved by PWeaker_trans
      as PWeaker_preorder.

In this case naturally symmetry will not work. Note that you are not required to provide the appropriate proof term directly in the relation declaration, you may use wildcards for coq to require the proofs interactively.

Remark: As said earlier, what is really going on is the typeclass mechanism. So all this is simply sugar for an instance declaration to the appropriate type class, Equivalence for example in the first case. We could have written instead:

Require Import Classes.RelationClasses.

Instance PEq_equiv: @Equivalence Pred PEq :=
 Equivalence_Reflexive := PEq_reflexive
 Equivalence_Symmetric := PEq_symm
 Equivalence_Transitive := PEq_trans.

2.1.2 Adding morphisms

The other typical case in which you might want to extend built-in tactics is the one of morphisms for which we would like to be able to use rewrite. Once again, we have syntactic sugar to avoir bothering explicitely with typeclasses. In the case of a binary function, it would look like this:

Add Parametric Morphism : f with
   signature (rel ==> rel ==> rel) as foo.

This one might seem a bit more cryptic. What is going on is that given a context, we want to be able to substitute a subterm for an other one given they are related by the relation rel. Said differently, we want to prove that f is a morphism with respect to rel, or that rel is compatible with f.

It is clearer with an example. Say we define the union of two predicates, we can actually rewrite any equivalent predicates under it.

Require Import Setoid.
Definition PJoin P1 P2: Pred := λ s, P1 s \/ P2 s.

Add Parametric Morphism : PJoin with
   signature (PEq ==> PEq ==> PEq) as foo.
Proof.
  intros Q1 Q1' eq1 Q2 Q2' eq2 s; split; intros H;
    (destruct H; [left; apply eq1; assumption | right; apply eq2; assumption]).
Qed.

coq asked us to prove that if four predicates are pairwise PEquivalent, their respective unions are PEquivalent. We therefore now are able to use the tactic rewrite to rewrite PEquivalences under unions in goals.

Note: beware, we only proved the compatibility of PEq with respect to the union! coq will complain if we try to rewrite PEquivalence under any other construction. The (Leibniz) equality has the peculiar property to be compatible with any context by definition.

Note bis: we have a very symmetric statement in the exemple using PEq everywhere, but that is not necessary. We could for instance assert compatibility only on the left by replacing the second PEq by an eq. An other reason of uniformity in the example is that the codomain of the function PJoin is the same as its arguments, but once again it could be otherwise. It notably is common to end up in Prop and therefore be interested in a result where the last PEq is replaced by iff: the proposition obtained after rewriting is guaranteed to be equivalent.

Finally, as was the case with relations, we can instead explicitely declare the adequate instance. The Typeclass at use here is Proper:

Instance foo: Proper (PEq ==> PEq ==> PEq) PJoin.
Proof.
  intros Q1 Q1' eq1 Q2 Q2' eq2 s; split; intros H;
    (destruct H; [left; apply eq1; assumption | right; apply eq2; assumption]).
Qed.

2.2 Using hint databases

2.2.1 Hint databases from the standard library

The auto (or its existential variant) tactics tries by default to solve a goal by exploring proofs trees, up to a fixed depth, that could be built using a fixed set of rules. These rules are defined in a so-called database, named core, essentially trying to unfold a few arithmetic and boolean functions from the standard library, and trying to apply a few lemmas and constructor over the elementary logical connectives. Its detail can be printed through the command:

Print HintDb core.

However, the auto tactics can be prompted to use another hint database. Are predefined the following, whose detail can be printed as seen previously: arith, zarith, bool, datatypes, sets and typeclassinstances. Note that the last one is automatically enriched when registering new instances for a typeclass, and used during resolution. The syntax to use a specific database is the following:

auto with db1 ... db2.

2.2.2 User-defined databases

One can also define its own databases, for instance to reduce a user defined expression to its normal-form via rewriting lemmas. Its creation is done through the Create HintDb command:

Create HintDb my_lovely_db.

The user can then enrich the database by adding hints to it. A hint is a lemma (actually more generally a term) and a way to use it:

  • by applying it (adds "simple apply term" to the db): keyword Resolve
  • by succeeding applying it (adds "simple apply term; trivial" to the db): keyword Immediate
  • by adding constructors of a type as Resolve hints: keyword Constructors
  • by allowing auto to unfold a definition: keyword Unfold
  • by applying any tactic: keyword Extern.

For instance:

Hint Resolve lemma1 lemma2: my_lovely_db.

For more details: https://coq.inria.fr/refman/Reference-Manual010.html#sec395

2.3 Computation

2.3.1 Compute

2.3.2 cbv

2.3.3 cbn

2.3.4 Simpl

2.3.5 NoteReflexivity

Reflexivity does more than simpl, it notably tries to unfold definitions.

3 Notations

3.1 Useful notations from the standard library

Importing the utf8 standard library defines a few convenient utf8-based notations. In particular an elegant way to define anonymous functions:

Require Import Utf8.

let f := λ x y, x + y.

3.2 Precedence levels

Go from 0 (tightest) to 100, with an additionnal special 200.

3.3 Associativity

No associativity Left associativity Right associativity

4 Working with Ltac

4.1 Matching on hypotheses and conclusions

4.1.1 Hypotheses

Looking for an hypothesis of the form P x y, for any x and y.

match goal with
  H : P ?x ?y |- _ => destruct H; auto
end.

This will fail if no such hypothesis exists. You can add try in front of it.

To match all such hypotheses, add repeat.

The following example shows how to use hypotheses matching to remove duplicates in hypotheses.

Goal P x y -> P x y -> P x z -> P x z -> P x z -> P y z.
Proof.
  intros.

  repeat match goal with
    H1 : P ?x ?y,
        H2: P ?x ?y |- _ => clear H1
  end.
Qed.

We try to match two hypotheses of the form P ?x ?y. The pattern matching is strong enough to express that H1 and H2 must refer to the same x and y. H1 and H2 are guaranteed to be different though.

It is also possible to match part of an hypothesis. Using context:

match goal with
  H : context [P ?x ?y] |- _ => (* do stuff *)
end.

4.1.2 Conclusions

The matching can also be made on the conlusion of the goal (after |-):

match goal with
  |- context [P ?x ?y] => (* do stuff *)
end.

Of course, multiple patterns can be matched.

repeat match goal with
  H : context [P ?x ?y] |- _ => (* do stuff *)
| |- context [P ?x ?y] => (* do stuff *)
end.

This will loop as long as either the hypotheses or the conclusion contain a term matching P ?x ?y. Be sure to remove the matching hypotheses to enforce termination.

4.2 Generate fresh names

Sometimes we need to generate fresh names inside tactics:

let n := fresh in (* generate new name, probably H0, H1, H2 *)
intro n

let n := fresh H in (* generate new name, based on the name of H *)
intro n

let n := fresh "H" in (* generate new name, based on the given string "H" *)
intro n

4.3 Print Ltac

One can view the Ltac code of a tactic (when it's actually written in Ltac).

Print Ltac inv.

--->
Ltac inv H := inversion H; clear H; subst

4.4 Working with PG

One can add custom keybindings to Emacs / PG. For example, to see the Ltac code of a tactic (see previous section), we can define the following Emacs lisp code in the appropriate file (~/.emacs= in my case)

(defun coq-Print-Ltac (withprintingall)
  "Ask for a tactic and Print Ltac it."
  (interactive "P")
  (if withprintingall
      (coq-ask-do-show-all "Print Ltac" "Print Ltac")
    (coq-ask-do "Print Ltac" "Print Ltac")))

(global-set-key (kbd "C-c C-$") 'coq-Print-Ltac)

(PW: I should investigate what occurences of "Print Ltac" stand for what)

5 Miscellaneous useful tricks

5.1 Keeping track of the ongoing case

If proceeding by induction or case studies over an inductive case, say a semantic judgment, it can be hard to spot which case we end up in. A useful hack is to keep track of a discriminating parameter. Assuming for example that we are about to inverse a judgment such as (i, σ) → (i', σ'), simply use the following tactics beforehand:

set (ii := i)

5.2 Duplicating an hypothesis

5.2.1 With remember

Ltac dup H :=
let H' := fresh "H" in
remember H as H'; clear HeqH'.

5.2.2 With generalize dependent

Ltac dup H :=
let H' := fresh "H" in
generalize dependent H; intros H'.

5.2.3 With assert

Ltac dup H :=
let n := fresh H in
assert (n := H)

5.3 Show the axioms used for a given lemma

To show what axioms a given lemma depends on, one can use the following vernacular command

Print Assumptions my_lemma.

6 Arguments

6.1 Implicit arguments

Implicit arguments are treated the same way as if provided as an _, but systematically. We can declare them at define time by putting curly brackets around the argument.

Inductive list {A : Type} : Type :=
 | nil : list
 | cons : A -> list -> list.

Afterwards, through the Arguments directive: name and list of arguments, curly brackets for the ones to be inferred.

Use an @ to disable implicit arguments locally.

Definition l : @list nat := ... .

6.2 Arguments renaming

Arguments can be used to rename arguments using the rename flag (:rename. at the end of the command). (PW: explain? example?)

7 Generalize dependent versus generalize versus revert

Starting from a goal

a, b : A
EQ : a = b
---------
  b = a

One can use different tactics to move hypotheses from the context to the goal.

revert EQ

a, b : A
---------
a = b -> b = a

OR

generalize EQ

a, b : A
EQ : a = b
---------
a = b -> b = a

Notice that the generalized hypothesis is still present in the context, contrary to the reverted one.

We can also generalize terms of type in Type.

generalize a

a, b : A
EQ : a = b
---------
forall a0: A, b = a0

Here we have lost some information, because the a in the context is no longer related to the new one. This situation is solved using generalize dependent.

generalize dependent a

b : A
---------
forall a : A, a = b -> b = a

8 Intro patterns

8.1 With square brackets

Conjunction: just a list with no separators Ex: [H1 [H2 H3]] or (H1 & H2 & H3) Disjunction: | Ex: [H1 | H2]

8.2 Tricks

<- or -> to rewrite directly an equality. _ clear the hypothesis directly ? to let coq choose the name

9 Pattern matching. Unify with intro patterns and talk about the let, let with the backstick

9.1 A particular case of pattern matching, the let-binding

Coq does not allow pattern matching over arguments of a function, as opposed to OCaml, even if the inductive type of this constructor admits a unique constructor. One can avoid an arguably heavy match using the let-binding construct:

Definition π1 (A B: Type) (x: A * B) -> A :=
let (a,b) := x in a.

Note however that by default, you can only destruct one layer of the argument. Using a tick allows you to destruct at arbitrary depth:

Definition π11 (A B C: Type) (x: (A * B) * C) -> A :=
let '((a,b),c) := x in a.

10 Switching and selecting goals

When several subgoals are left to solve, it is possible to solve some goals before others (either because you don't feel in the mood for a given subgoal or because solving some goal will instantiate lots of existential variables, making it easier to solve the remaining goals afterwards).

10.1 Switching to a specific goal

You can switch to solve goal num with the Focus vernacular command:

Focus 2.

10.2 Goal selectors.

When the proof of the n-th goal is fairly easy, i.e. it is doable in a single tactic, we can use goal selectors that look more lightweight.

To apply tactic tac to the n-th subgoal:

n: tac.

10.2.1 In 8.5, the all: selector

In Coq 8.5, the all: selector applies a given tactic to all goals. This seems very handy in cases where a eapply has generated lots of existentials, most of which would be solved in a particular subgoal. The strategy I would use here is to apply some tactic to the most discriminant subgoal and then call auto or eauto on the rest of the subgoals.

n: tac.
all: auto.

11 Emacs extensions: Proof-General and Company-coq

11.1 Proof-General

Proof-General is an Emacs interface for proof assistants such as Coq. The latest version is available on GitHub.

11.2 Company-coq

Company-coq is an extension for Proof-General's Coq mode. It is available through MELPA. One of its most interesting feature is prettification. For example, adding the following bits of code into your `~/.emacs` will visually replace all alpha with an α.

(add-hook 'coq-mode-hook #'company-coq-initialize)
(add-hook 'coq-mode-hook
          (lambda ()
            (set (make-local-variable 'prettify-symbols-alist)
                 '(("Admitted." . ?😱) ("admit." . ?😱)
  ("Alpha" . ?Α) ("Beta" . ?Β) ("Gamma" . ?Γ)
  ("Delta" . ?Δ) ("Epsilon" . ?Ε) ("Zeta" . ?Ζ)
  ("Eta" . ?Η) ("Theta" . ?Θ) ("Iota" . ?Ι)
  ("Kappa" . ?Κ) ("Lambda" . ?Λ) ("Mu" . ?Μ)
  ("Nu" . ?Ν) ("Xi" . ?Ξ) ("Omicron" . ?Ο)
  ("Pi" . ?Π) ("Rho" . ?Ρ) ("Sigma" . ?Σ)
  ("Tau" . ?Τ) ("Upsilon" . ?Υ) ("Phi" . ?Φ)
  ("Chi" . ?Χ) ("Psi" . ?Ψ) ("Omega" . ?Ω)
  ("alpha" . ?α) ("beta" . ?β) ("gamma" . ?γ)
  ("delta" . ?δ) ("epsilon" . ?ε) ("zeta" . ?ζ)
  ("eta" . ?η) ("theta" . ?θ) ("iota" . ?ι)
  ("kappa" . ?κ) ("lambda" . ?λ) ("mu" . ?μ)
  ("nu" . ?ν) ("xi" . ?ξ) ("omicron" . ?ο)
  ("pi" . ?π) ("rho" . ?ρ) ("sigma" . ?σ)
  ("tau" . ?τ) ("upsilon" . ?υ) ("phi" . ?φ)
  ("chi" . ?χ) ("psi" . ?ψ) ("omega" . ?ω)
  ))))

You will however need to use a font that can handle unicode. For example on OS X, you may need to add the following code into your `~/.emacs`:

(set-fontset-font t 'unicode (font-spec :name "Apple Color Emoji") nil 'append)

12 TODO : PG, companycoq, useful commands

Author: Platypus

Created: 2016-09-08 Thu 12:05

Emacs 24.3.1 (Org mode 8.2.4)

Validate