Reasoning with inductive types — Coq 8.14.1 documentation

\[\begin{split}\newcommand{\as}{\kw{as}} \newcommand{\Assum}[3]{\kw{Assum}(#1)(#2:#3)} \newcommand{\case}{\kw{case}} \newcommand{\cons}{\textsf{cons}} \newcommand{\consf}{\textsf{consf}} \newcommand{\Def}[4]{\kw{Def}(#1)(#2:=#3:#4)} \newcommand{\emptyf}{\textsf{emptyf}} \newcommand{\End}{\kw{End}} \newcommand{\kwend}{\kw{end}} \newcommand{\even}{\textsf{even}} \newcommand{\evenO}{\textsf{even}_\textsf{O}} \newcommand{\evenS}{\textsf{even}_\textsf{S}} \newcommand{\Fix}{\kw{Fix}} \newcommand{\fix}{\kw{fix}} \newcommand{\for}{\textsf{for}} \newcommand{\forest}{\textsf{forest}} \newcommand{\Functor}{\kw{Functor}} \newcommand{\In}{\kw{in}} \newcommand{\Ind}[4]{\kw{Ind}[#2](#3:=#4)} \newcommand{\ind}[3]{\kw{Ind}~[#1]\left(#2\mathrm{~:=~}#3\right)} \newcommand{\Indp}[5]{\kw{Ind}_{#5}(#1)[#2](#3:=#4)} \newcommand{\Indpstr}[6]{\kw{Ind}_{#5}(#1)[#2](#3:=#4)/{#6}} \newcommand{\injective}{\kw{injective}} \newcommand{\kw}[1]{\textsf{#1}} \newcommand{\length}{\textsf{length}} \newcommand{\letin}[3]{\kw{let}~#1:=#2~\kw{in}~#3} \newcommand{\List}{\textsf{list}} \newcommand{\lra}{\longrightarrow} \newcommand{\Match}{\kw{match}} \newcommand{\Mod}[3]{{\kw{Mod}}({#1}:{#2}\,\zeroone{:={#3}})} \newcommand{\ModImp}[3]{{\kw{Mod}}({#1}:{#2}:={#3})} \newcommand{\ModA}[2]{{\kw{ModA}}({#1}=={#2})} \newcommand{\ModS}[2]{{\kw{Mod}}({#1}:{#2})} \newcommand{\ModType}[2]{{\kw{ModType}}({#1}:={#2})} \newcommand{\mto}{.\;} \newcommand{\nat}{\textsf{nat}} \newcommand{\Nil}{\textsf{nil}} \newcommand{\nilhl}{\textsf{nil\_hl}} \newcommand{\nO}{\textsf{O}} \newcommand{\node}{\textsf{node}} \newcommand{\nS}{\textsf{S}} \newcommand{\odd}{\textsf{odd}} \newcommand{\oddS}{\textsf{odd}_\textsf{S}} \newcommand{\ovl}[1]{\overline{#1}} \newcommand{\Pair}{\textsf{pair}} \newcommand{\plus}{\mathsf{plus}} \newcommand{\SProp}{\textsf{SProp}} \newcommand{\Prop}{\textsf{Prop}} \newcommand{\return}{\kw{return}} \newcommand{\Set}{\textsf{Set}} \newcommand{\Sort}{\mathcal{S}} \newcommand{\Str}{\textsf{Stream}} \newcommand{\Struct}{\kw{Struct}} \newcommand{\subst}[3]{#1\{#2/#3\}} \newcommand{\tl}{\textsf{tl}} \newcommand{\tree}{\textsf{tree}} \newcommand{\trii}{\triangleright_\iota} \newcommand{\Type}{\textsf{Type}} \newcommand{\WEV}[3]{\mbox{$#1[] \vdash #2 \lra #3$}} \newcommand{\WEVT}[3]{\mbox{$#1[] \vdash #2 \lra$}\\ \mbox{$ #3$}} \newcommand{\WF}[2]{{\mathcal{W\!F}}(#1)[#2]} \newcommand{\WFE}[1]{\WF{E}{#1}} \newcommand{\WFT}[2]{#1[] \vdash {\mathcal{W\!F}}(#2)} \newcommand{\WFTWOLINES}[2]{{\mathcal{W\!F}}\begin{array}{l}(#1)\\\mbox{}[{#2}]\end{array}} \newcommand{\with}{\kw{with}} \newcommand{\WS}[3]{#1[] \vdash #2 <: #3} \newcommand{\WSE}[2]{\WS{E}{#1}{#2}} \newcommand{\WT}[4]{#1[#2] \vdash #3 : #4} \newcommand{\WTE}[3]{\WT{E}{#1}{#2}{#3}} \newcommand{\WTEG}[2]{\WTE{\Gamma}{#1}{#2}} \newcommand{\WTM}[3]{\WT{#1}{}{#2}{#3}} \newcommand{\zeroone}[1]{[{#1}]} \end{split}\]

# Reasoning with inductive types

## Applying constructors

The tactics presented here specialize `apply` (and `eapply`) to the case of constructors of inductive types.

Tactic constructor natural

  This tactic applies to a goal such that its conclusion is an inductive type (say `I`). The argument `natural` must be less or equal to the numbers of constructor(s) of `I`. Let `ci` be the i-th constructor of `I`, then `constructor i` is equivalent to `intros; apply ci`.

  Error Not an inductive product.
  Error Not enough constructors.
  Variant constructor

    This tries `constructor 1` then `constructor 2`, ..., then `constructor n` where `n` is the number of constructors of the head of the goal.

  Variant constructor natural with bindings

    Let `c` be the i-th constructor of `I`, then `constructor i with bindings` is equivalent to `intros; apply c with bindings`.

    Warning

    The terms in `bindings` are checked in the context where constructor is executed and not in the context where `apply` is executed (the introductions are not taken into account).

  Variant split with bindings?

    This applies only if `I` has a single constructor. It is then equivalent to `constructor 1 with bindings?`. It is typically used in the case of a conjunction \(A \wedge B\).

    Variant exists bindings

      This applies only if `I` has a single constructor. It is then equivalent to `intros; constructor 1 with bindings.` It is typically used in the case of an existential quantification \(\exists x, P(x).\)

    Variant exists bindings+,

      This iteratively applies `exists bindings`.

    Error Not an inductive goal with 1 constructor.
  Variant left with bindings?
  Variant right with bindings?

    These tactics apply only if `I` has two constructors, for instance in the case of a disjunction \(A \vee B\). Then, they are respectively equivalent to `constructor 1 with bindings?` and `constructor 2 with bindings?`.

    Error Not an inductive goal with 2 constructors.
  Variant econstructor
  Variant eexists
  Variant esplit
  Variant eleft
  Variant eright

    These tactics and their variants behave like `constructor`, `exists`, `split`, `left`, `right` and their variants but they introduce existential variables instead of failing when the instantiation of a variable cannot be found (cf. `eapply` and `apply`).

## Case analysis and induction

The tactics presented in this section implement induction or case analysis on inductive or co-inductive objects (see Theory of inductive definitions).

Tactic destruct term

  This tactic applies to any goal. The argument `term` must be of inductive or co-inductive type and the tactic generates subgoals, one for each possible form of `term`, i.e. one for each constructor of the inductive or co-inductive type. Unlike `induction`, no induction hypothesis is generated by `destruct`.

  Variant destruct ident

    If `ident` denotes a quantified variable of the conclusion of the goal, then `destruct ident` behaves as `intros until ident; destruct ident`. If `ident` is not anymore dependent in the goal after application of `destruct`, it is erased (to avoid erasure, use parentheses, as in `destruct (ident)`).

    If `ident` is a hypothesis of the context, and `ident` is not anymore dependent in the goal after application of `destruct`, it is erased (to avoid erasure, use parentheses, as in `destruct (ident)`).

  Variant destruct natural

    > `destruct natural` behaves as `intros until natural` followed by destruct applied to the last introduced hypothesis.

    Note

    For destruction of a number, use syntax `destruct (natural)` (not very interesting anyway).

  Variant destruct pattern

    The argument of `destruct` can also be a pattern of which holes are denoted by “_”. In this case, the tactic checks that all subterms matching the pattern in the conclusion and the hypotheses are compatible and performs case analysis using this subterm.

  Variant destruct term+,

    This is a shortcut for `destruct term; ...; destruct term`.

  Variant destruct term as or_and_intropattern_loc

    This behaves as `destruct term` but uses the names in `or_and_intropattern_loc` to name the variables introduced in the context. The `or_and_intropattern_loc` must have the form `[p11 ... p1n | ... | pm1 ... pmn ]` with `m` being the number of constructors of the type of `term`. Each variable introduced by `destruct` in the context of the `i`-th goal gets its name from the list `pi1 ... pin` in order. If there are not enough names, `destruct` invents names for the remaining variables to introduce. More generally, the `pij` can be any introduction pattern (see `intros`). This provides a concise notation for chaining destruction of a hypothesis.

  Variant destruct term eqn: naming_intropattern

    This behaves as `destruct term` but adds an equation between `term` and the value that it takes in each of the possible cases. The name of the equation is specified by `naming_intropattern` (see `intros`), in particular `?` can be used to let Coq generate a fresh name.

  Variant destruct term with bindings

    This behaves like `destruct term` providing explicit instances for the dependent premises of the type of `term`.

  Variant edestruct term

    This tactic behaves like `destruct term` except that it does not fail if the instance of a dependent premises of the type of `term` is not inferable. Instead, the unresolved instances are left as existential variables to be inferred later, in the same way as `eapply` does.

  Variant destruct term using term with bindings?

    This is synonym of `induction term using term with bindings?`.

  Variant destruct term in goal_occurrences

    This syntax is used for selecting which occurrences of `term` the case analysis has to be done on. The `in goal_occurrences` clause is an occurrence clause whose syntax and behavior is described in occurrences sets.

  Variant destruct term with bindings? as or_and_intropattern_loc? eqn: naming_intropattern? using term with bindings?? in goal_occurrences?
  Variant edestruct term with bindings? as or_and_intropattern_loc? eqn: naming_intropattern? using term with bindings?? in goal_occurrences?

    These are the general forms of `destruct` and `edestruct`. They combine the effects of the `with`, `as`, `eqn:`, `using`, and `in` clauses.

Tactic case term

  The tactic `case` is a more basic tactic to perform case analysis without recursion. It behaves as `elim term` but using a case-analysis elimination principle and not a recursive one.

Variant case term with bindings

  Analogous to `elim term with bindings` above.

Variant ecase term with bindings?

  In case the type of `term` has dependent premises, or dependent premises whose values are not inferable from the `with bindings` clause, `ecase` turns them into existential variables to be resolved later on.

Variant simple destruct ident

  This tactic behaves as `intros until ident; case ident` when `ident` is a quantified variable of the goal.

Variant simple destruct natural

  This tactic behaves as `intros until natural; case ident` where `ident` is the name given by `intros until natural` to the `natural` -th non-dependent premise of the goal.

Variant case_eq term

  The tactic `case_eq` is a variant of the `case` tactic that allows to perform case analysis on a term without completely forgetting its original form. This is done by generating equalities between the original form of the term and the outcomes of the case analysis.

Tactic induction term

  This tactic applies to any goal. The argument `term` must be of inductive type and the tactic `induction` generates subgoals, one for each possible form of `term`, i.e. one for each constructor of the inductive type.

  If the argument is dependent in either the conclusion or some hypotheses of the goal, the argument is replaced by the appropriate constructor form in each of the resulting subgoals and induction hypotheses are added to the local context using names whose prefix is IH.

  There are particular cases:

  - If term is an identifier `ident` denoting a quantified variable of the conclusion of the goal, then inductionident behaves as `intros until ident; induction ident`. If `ident` is not anymore dependent in the goal after application of `induction`, it is erased (to avoid erasure, use parentheses, as in `induction (ident)`).

  - If `term` is a `natural`, then `induction natural` behaves as `intros until natural` followed by `induction` applied to the last introduced hypothesis.

    Note

    For simple induction on a number, use syntax induction (number) (not very interesting anyway).

  - In case term is a hypothesis `ident` of the context, and `ident` is not anymore dependent in the goal after application of `induction`, it is erased (to avoid erasure, use parentheses, as in `induction (ident)`).

  - The argument `term` can also be a pattern of which holes are denoted by “_”. In this case, the tactic checks that all subterms matching the pattern in the conclusion and the hypotheses are compatible and performs induction using this subterm.

Example

Lemma induction_test : forall n: nat, n = n -> n <= n.
  1 goal ============================ forall n : nat, n = n -> n <= n
intros n H.
  1 goal n : nat H : n = n ============================ n <= n
induction n.
  2 goals H : 0 = 0 ============================ 0 <= 0 goal 2 is: S n <= S n
exact (le_n 0).
  1 goal n : nat H : S n = S n IHn : n = n -> n <= n ============================ S n <= S n

Error Not an inductive product.

Error Unable to find an instance for the variables ident ... ident.

  Use in this case the variant `elim … with` below.

Variant induction term as or_and_intropattern_loc

  This behaves as `induction` but uses the names in `or_and_intropattern_loc` to name the variables introduced in the context. The `or_and_intropattern_loc` must typically be of the form `[ p` 11 `... p` 1n `| ... | p`m1 `... p`mn `]` with `m` being the number of constructors of the type of `term`. Each variable introduced by induction in the context of the i-th goal gets its name from the list `p`i1 `... p`in in order. If there are not enough names, induction invents names for the remaining variables to introduce. More generally, the `p`ij can be any disjunctive/conjunctive introduction pattern (see `intros …`). For instance, for an inductive type with one constructor, the pattern notation `(p`1 `, ... , p`n `)` can be used instead of `[ p`1 `... p`n `]`.

Variant induction term with bindings

  This behaves like `induction` providing explicit instances for the premises of the type of `term` (see Bindings).

Variant einduction term

  This tactic behaves like `induction` except that it does not fail if some dependent premise of the type of `term` is not inferable. Instead, the unresolved premises are posed as existential variables to be inferred later, in the same way as `eapply` does.

Variant induction term using term

  This behaves as `induction` but using `term` as induction scheme. It does not expect the conclusion of the type of the first `term` to be inductive.

Variant induction term using term with bindings

  This behaves as `induction … using …` but also providing instances for the premises of the type of the second `term`.

Variant induction term+, using qualid

  This syntax is used for the case `qualid` denotes an induction principle with complex predicates as the induction principles generated by `Function` or `Functional Scheme` may be.

Variant induction term in goal_occurrences

  This syntax is used for selecting which occurrences of `term` the induction has to be carried on. The `in goal_occurrences` clause is an occurrence clause whose syntax and behavior is described in occurrences sets. If variables or hypotheses not mentioning `term` in their type are listed in `goal_occurrences`, those are generalized as well in the statement to prove.

  Example

  Lemma comm x y : x + y = y + x.
    1 goal x, y : nat ============================ x + y = y + x
  induction y in x |- *.
    2 goals x : nat ============================ x + 0 = 0 + x goal 2 is: x + S y = S y + x
  Show 2.
    goal 2 is: x, y : nat IHy : forall x : nat, x + y = y + x ============================ x + S y = S y + x

Variant induction term with bindings as or_and_intropattern_loc using term with bindings in goal_occurrences
Variant einduction term with bindings as or_and_intropattern_loc using term with bindings in goal_occurrences

  These are the most general forms of `induction` and `einduction`. It combines the effects of the with, as, using, and in clauses.

Variant elim term

  This is a more basic induction tactic. Again, the type of the argument `term` must be an inductive type. Then, according to the type of the goal, the tactic `elim` chooses the appropriate destructor and applies it as the tactic `apply` would do. For instance, if the local context contains `n:nat` and the current goal is `T` of type `Prop`, then `elim n` is equivalent to `apply nat_ind with (n:=n)`. The tactic `elim` does not modify the context of the goal, neither introduces the induction loading into the context of hypotheses. More generally, `elim term` also works when the type of `term` is a statement with premises and whose conclusion is inductive. In that case the tactic performs induction on the conclusion of the type of `term` and leaves the non-dependent premises of the type as subgoals. In the case of dependent products, the tactic tries to find an instance for which the elimination lemma applies and fails otherwise.

Variant elim term with bindings

  Allows to give explicit instances to the premises of the type of `term` (see Bindings).

Variant eelim term

  In case the type of `term` has dependent premises, this turns them into existential variables to be resolved later on.

Variant elim term using term
Variant elim term using term with bindings

  Allows the user to give explicitly an induction principle `term` that is not the standard one for the underlying inductive type of `term`. The `bindings` clause allows instantiating premises of the type of `term`.

Variant elim term with bindings using term with bindings
Variant eelim term with bindings using term with bindings

  These are the most general forms of `elim` and `eelim`. It combines the effects of the `using` clause and of the two uses of the `with` clause.

Variant elimtype type

  The argument `type` must be inductively defined. `elimtype I` is equivalent to `cut I. intro Hn; elim Hn; clear Hn.` Therefore the hypothesis `Hn` will not appear in the context(s) of the subgoal(s). Conversely, if `t` is a `term` of (inductive) type `I` that does not occur in the goal, then `elim t` is equivalent to `elimtype I; 2:exact t.`

Variant simple induction ident

  This tactic behaves as `intros until ident; elim ident` when `ident` is a quantified variable of the goal.

Variant simple induction natural

  This tactic behaves as `intros until natural; elim ident` where `ident` is the name given by `intros until natural` to the `natural`-th non-dependent premise of the goal.

Tactic dependent induction ident

  The experimental tactic dependent induction performs induction- inversion on an instantiated inductive predicate. One needs to first require the Coq.Program.Equality module to use this tactic. The tactic is based on the BasicElim tactic by Conor McBride [McB00] and the work of Cristina Cornes around inversion [CT95]. From an instantiated inductive predicate and a goal, it generates an equivalent goal where the hypothesis has been generalized over its indexes which are then constrained by equalities to be the right instances. This permits to state lemmas without resorting to manually adding these equalities and still get enough information in the proofs.

Example

Lemma lt_1_r : forall n: nat, n < 1 -> n = 0.
  1 goal ============================ forall n : nat, n < 1 -> n = 0
intros n H ; induction H.
  2 goals n : nat ============================ n = 0 goal 2 is: n = 0

Here we did not get any information on the indexes to help fulfill this proof. The problem is that, when we use the `induction` tactic, we lose information on the hypothesis instance, notably that the second argument is 1 here. Dependent induction solves this problem by adding the corresponding equality to the context.

Require Import Coq.Program.Equality.
Lemma lt_1_r : forall n: nat, n < 1 -> n = 0.
  1 goal ============================ forall n : nat, n < 1 -> n = 0
intros n H ; dependent induction H.
  2 goals ============================ 0 = 0 goal 2 is: n = 0

The subgoal is cleaned up as the tactic tries to automatically simplify the subgoals with respect to the generated equalities. In this enriched context, it becomes possible to solve this subgoal.

reflexivity.
  1 goal n : nat H : S n <= 0 IHle : 0 = 1 -> n = 0 ============================ n = 0

Now we are in a contradictory context and the proof can be solved.

inversion H.
  No more goals.

This technique works with any inductive predicate. In fact, the `dependent induction` tactic is just a wrapper around the `induction` tactic. One can make its own variant by just writing a new tactic based on the definition found in `Coq.Program.Equality`.

Variant dependent induction ident generalizing ident+

  This performs dependent induction on the hypothesis `ident` but first generalizes the goal by the given variables so that they are universally quantified in the goal. This is generally what one wants to do with the variables that are inside some constructors in the induction hypothesis. The other ones need not be further generalized.

Variant dependent destruction ident

  This performs the generalization of the instance `ident` but uses `destruct` instead of induction on the generalized hypothesis. This gives results equivalent to `inversion` or `dependent inversion` if the hypothesis is dependent.

See also the larger example of `dependent induction` and an explanation of the underlying technique.

See also

`functional induction`

Tactic discriminate term

  This tactic proves any goal from an assumption stating that two structurally different `term`s of an inductive set are equal. For example, from `(S (S O))=(S O)` we can derive by absurdity any proposition.

  The argument `term` is assumed to be a proof of a statement of conclusion `term = term` with the two terms being elements of an inductive set. To build the proof, the tactic traverses the normal forms 1 of the terms looking for a couple of subterms `u` and `w` (`u` subterm of the normal form of `term` and `w` subterm of the normal form of `term`), placed at the same positions and whose head symbols are two different constructors. If such a couple of subterms exists, then the proof of the current goal is completed, otherwise the tactic fails.

Note

The syntax `discriminate ident` can be used to refer to a hypothesis quantified in the goal. In this case, the quantified hypothesis whose name is `ident` is first introduced in the local context using `intros until ident`.

Error No primitive equality found.

Error Not a discriminable equality.

Variant discriminate natural

  This does the same thing as `intros until natural` followed by `discriminate ident` where `ident` is the identifier for the last introduced hypothesis.

Variant discriminate term with bindings

  This does the same thing as `discriminate term` but using the given bindings to instantiate parameters or hypotheses of `term`.

Variant ediscriminate natural
Variant ediscriminate term with bindings?

  This works the same as `discriminate` but if the type of `term`, or the type of the hypothesis referred to by `natural`, has uninstantiated parameters, these parameters are left as existential variables.

Variant discriminate

  This behaves like `discriminate ident` if ident is the name of an hypothesis to which `discriminate` is applicable; if the current goal is of the form `term <> term`, this behaves as `intro ident; discriminate ident`.

  Error No discriminable equalities.

Tactic injection term

  The injection tactic exploits the property that constructors of inductive types are injective, i.e. that if `c` is a constructor of an inductive type and `c t`1 and `c t`2 are equal then `t`1 and `t`2 are equal too.

  If `term` is a proof of a statement of conclusion `term = term`, then `injection` applies the injectivity of constructors as deep as possible to derive the equality of all the subterms of `term` and `term` at positions where the terms start to differ. For example, from `(S p, S n) = (q, S (S m))` we may derive `S p = q` and `n = S m`. For this tactic to work, the terms should be typed with an inductive type and they should be neither convertible, nor having a different head constructor. If these conditions are satisfied, the tactic derives the equality of all the subterms at positions where they differ and adds them as antecedents to the conclusion of the current goal.

  Example

  Consider the following goal:

  Inductive list : Set := | nil : list | cons : nat -> list -> list.
    list is defined list_rect is defined list_ind is defined list_rec is defined list_sind is defined
  Parameter P : list -> Prop.
    P is declared
  Goal forall l n, P nil -> cons n l = cons 0 nil -> P l.
    1 goal ============================ forall (l : list) (n : nat), P nil -> cons n l = cons 0 nil -> P l
  intros.
    1 goal l : list n : nat H : P nil H0 : cons n l = cons 0 nil ============================ P l
  injection H0.
    1 goal l : list n : nat H : P nil H0 : cons n l = cons 0 nil ============================ l = nil -> n = 0 -> P l

  Beware that injection yields an equality in a sigma type whenever the injected object has a dependent type `P` with its two instances in different types `(P t`1 `... t`n `)` and `(P u`1 `... u`n ). If `t`1 and `u`1 are the same and have for type an inductive type for which a decidable equality has been declared using `Scheme` `Equality ...` (see Generation of induction principles with Scheme), the use of a sigma type is avoided.

  Note

  If some quantified hypothesis of the goal is named `ident`, then `injection ident` first introduces the hypothesis in the local context using `intros until ident`.

  Error Nothing to do, it is an equality between convertible terms.
  Error Not a primitive equality.
  Error Nothing to inject.

    This error is given when one side of the equality is not a constructor.

  Variant injection natural

    This does the same thing as `intros until natural` followed by `injection ident` where `ident` is the identifier for the last introduced hypothesis.

  Variant injection term with bindings

    This does the same as `injection term` but using the given bindings to instantiate parameters or hypotheses of `term`.

  Variant einjection natural
  Variant einjection term with bindings?

    This works the same as `injection` but if the type of `term`, or the type of the hypothesis referred to by `natural`, has uninstantiated parameters, these parameters are left as existential variables.

  Variant injection

    If the current goal is of the form `term <> term` , this behaves as `intro ident; injection ident`.

    Error goal does not satisfy the expected preconditions.
  Variant injection term with bindings? as simple_intropattern+
  Variant injection natural as simple_intropattern+
  Variant injection as simple_intropattern+
  Variant einjection term with bindings? as simple_intropattern+
  Variant einjection natural as simple_intropattern+
  Variant einjection as simple_intropattern+

    These variants apply `intros simple_intropattern+` after the call to `injection` or `einjection` so that all equalities generated are moved in the context of hypotheses. The number of `simple_intropattern` must not exceed the number of equalities newly generated. If it is smaller, fresh names are automatically generated to adjust the list of `simple_intropattern` to the number of new equalities. The original equality is erased if it corresponds to a hypothesis.

  Variant injection term with bindings? as injection_intropattern
  Variant injection natural as injection_intropattern
  Variant injection as injection_intropattern
  Variant einjection term with bindings? as injection_intropattern
  Variant einjection natural as injection_intropattern
  Variant einjection as injection_intropattern

    These are equivalent to the previous variants but using instead the syntax `injection_intropattern` which `intros` uses. In particular `as [= simple_intropattern+]` behaves the same as `as simple_intropattern+`.

  Flag Structural Injection

    This flag ensures that `injection term` erases the original hypothesis and leaves the generated equalities in the context rather than putting them as antecedents of the current goal, as if giving `injection term as` (with an empty list of names). This flag is off by default.

  Flag Keep Proof Equalities

    By default, `injection` only creates new equalities between `term`s whose type is in sort `Type` or `Set`, thus implementing a special behavior for objects that are proofs of a statement in `Prop`. This flag controls this behavior.

Tactic inversion ident

  Let the type of `ident` in the local context be `(I t)`, where `I` is a (co)inductive predicate. Then, `inversion` applied to `ident` derives for each possible constructor `c i` of `(I t)`, all the necessary conditions that should hold for the instance `(I t)` to be proved by `c i`.

Note

If `ident` does not denote a hypothesis in the local context but refers to a hypothesis quantified in the goal, then the latter is first introduced in the local context using `intros until ident`.

Note

As `inversion` proofs may be large in size, we recommend the user to stock the lemmas whenever the same instance needs to be inverted several times. See Generation of inversion principles with Derive Inversion.

Note

Part of the behavior of the `inversion` tactic is to generate equalities between expressions that appeared in the hypothesis that is being processed. By default, no equalities are generated if they relate two proofs (i.e. equalities between `term`s whose type is in sort `Prop`). This behavior can be turned off by using the `Keep Proof Equalities` setting.

Variant inversion natural

  This does the same thing as `intros until natural` then `inversion ident` where `ident` is the identifier for the last introduced hypothesis.

Variant inversion_clear ident

  This behaves as `inversion` and then erases `ident` from the context.

Variant inversion ident as or_and_intropattern_loc

  This generally behaves as inversion but using names in `or_and_intropattern_loc` for naming hypotheses. The `or_and_intropattern_loc` must have the form `[p`11 `... p`1n `| ... | p`m1 `... p`mn `]` with `m` being the number of constructors of the type of `ident`. Be careful that the list must be of length `m` even if `inversion` discards some cases (which is precisely one of its roles): for the discarded cases, just use an empty list (i.e. `n = 0`).The arguments of the i-th constructor and the equalities that `inversion` introduces in the context of the goal corresponding to the i-th constructor, if it exists, get their names from the list `p`i1 `... p`in in order. If there are not enough names, `inversion` invents names for the remaining variables to introduce. In case an equation splits into several equations (because `inversion` applies `injection` on the equalities it generates), the corresponding name `p`ij in the list must be replaced by a sublist of the form `[p`ij1 `... p`ijq `]` (or, equivalently, `(p`ij1 `, ..., p`ijq `)`) where `q` is the number of subequalities obtained from splitting the original equation. Here is an example. The `inversion ... as` variant of `inversion` generally behaves in a slightly more expectable way than `inversion` (no artificial duplication of some hypotheses referring to other hypotheses). To take benefit of these improvements, it is enough to use `inversion ... as []`, letting the names being finally chosen by Coq.

  Example

  Inductive contains0 : list nat -> Prop := | in_hd : forall l, contains0 (0 :: l) | in_tl : forall l b, contains0 l -> contains0 (b :: l).
    contains0 is defined contains0_ind is defined contains0_sind is defined
  Goal forall l: list nat, contains0 (1 :: l) -> contains0 l.
    1 goal ============================ forall l : list nat, contains0 (1 :: l) -> contains0 l
  intros l H; inversion H as [ | l' p Hl' [Heqp Heql'] ].
    1 goal l : list nat H : contains0 (1 :: l) l' : list nat p : nat Hl' : contains0 l Heqp : p = 1 Heql' : l' = l ============================ contains0 l

Variant inversion natural as or_and_intropattern_loc

  This allows naming the hypotheses introduced by `inversion natural` in the context.

Variant inversion_clear ident as or_and_intropattern_loc

  This allows naming the hypotheses introduced by `inversion_clear` in the context. Notice that hypothesis names can be provided as if `inversion` were called, even though the `inversion_clear` will eventually erase the hypotheses.

Variant inversion ident in ident+

  Let `ident+` be identifiers in the local context. This tactic behaves as generalizing `ident+`, and then performing `inversion`.

Variant inversion ident as or_and_intropattern_loc in ident+

  This allows naming the hypotheses introduced in the context by `inversion ident in ident+`.

Variant inversion_clear ident in ident+

  Let `ident+` be identifiers in the local context. This tactic behaves as generalizing `ident+`, and then performing `inversion_clear`.

Variant inversion_clear ident as or_and_intropattern_loc in ident+

  This allows naming the hypotheses introduced in the context by `inversion_clear ident in ident+`.

Variant dependent inversion ident

  That must be used when `ident` appears in the current goal. It acts like `inversion` and then substitutes `ident` for the corresponding `@term` in the goal.

Variant dependent inversion ident as or_and_intropattern_loc

  This allows naming the hypotheses introduced in the context by `dependent inversion ident`.

Variant dependent inversion_clear ident

  Like `dependent inversion`, except that `ident` is cleared from the local context.

Variant dependent inversion_clear ident as or_and_intropattern_loc

  This allows naming the hypotheses introduced in the context by `dependent inversion_clear ident`.

Variant dependent inversion ident with term

  This variant allows you to specify the generalization of the goal. It is useful when the system fails to generalize the goal automatically. If `ident` has type `(I t)` and `I` has type `forall (x:T), s`, then `term` must be of type `I:forall (x:T), I x -> s'` where `s'` is the type of the goal.

Variant dependent inversion ident as or_and_intropattern_loc with term

  This allows naming the hypotheses introduced in the context by `dependent inversion ident with term`.

Variant dependent inversion_clear ident with term

  Like `dependent inversion … with …` with but clears `ident` from the local context.

Variant dependent inversion_clear ident as or_and_intropattern_loc with term

  This allows naming the hypotheses introduced in the context by `dependent inversion_clear ident with term`.

Variant simple inversion ident

  It is a very primitive inversion tactic that derives all the necessary equalities but it does not simplify the constraints as `inversion` does.

Variant simple inversion ident as or_and_intropattern_loc

  This allows naming the hypotheses introduced in the context by `simple inversion`.

Tactic inversion ident using ident

  Let `ident` have type `(I t)` (`I` an inductive predicate) in the local context, and `ident` be a (dependent) inversion lemma. Then, this tactic refines the current goal with the specified lemma.

Variant inversion ident using ident in ident+

  This tactic behaves as generalizing `ident+`, then doing `inversion ident using ident`.

Variant inversion_sigma ident as simple_intropattern??

  This tactic turns equalities of dependent pairs (e.g., `existT P x p = existT P y q`, frequently left over by inversion on a dependent type family) into pairs of equalities (e.g., a hypothesis `H : x = y` and a hypothesis of type `rew H in p = q`); these hypotheses can subsequently be simplified using `subst`, without ever invoking any kind of axiom asserting uniqueness of identity proofs. If you want to explicitly specify the hypothesis to be inverted, you can pass it as an argument to `inversion_sigma`. This tactic also works for `sig`, `sigT2`, `sig2`, `ex`, and `ex2` and there are similar `eq_sig` `***_rect` induction lemmas.

  Error Type of ident is not an equality of recognized Σ types: expected one of sig sig2 sigT sigT2 sigT2 ex or ex2 but got term

    When applied to a hypothesis, `inversion_sigma` can only handle equalities of the listed sigma types.

  Error ident is not an equality of Σ types

    When applied to a hypothesis, `inversion_sigma` can only be called on hypotheses that are equalities using `Coq.Logic.Init.eq`.

Example

Non-dependent inversion.

Let us consider the relation `Le` over natural numbers:

Inductive Le : nat -> nat -> Set := | LeO : forall n: nat, Le 0 n | LeS : forall n m: nat, Le n m -> Le (S n) (S m).
  Le is defined Le_rect is defined Le_ind is defined Le_rec is defined Le_sind is defined

Let us consider the following goal:

Section Section.
Variable P : nat -> nat -> Prop.
  P is declared
Variable Q : forall n m: nat, Le n m -> Prop.
  Q is declared
Goal forall n m, Le (S n) m -> P n m.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop ============================ forall n m : nat, Le (S n) m -> P n m

intros.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m : nat H : Le (S n) m ============================ P n m

To prove the goal, we may need to reason by cases on `H` and to derive that `m` is necessarily of the form `(S m0)` for certain `m0` and that `(Le n m0)`. Deriving these conditions corresponds to proving that the only possible constructor of `(Le (S n) m)` is `LeS` and that we can invert the arrow in the type of `LeS`. This inversion is possible because `Le` is the smallest set closed by the constructors `LeO` and `LeS`.

inversion_clear H.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m, m0 : nat H0 : Le n m0 ============================ P n (S m0)

Note that `m` has been substituted in the goal for `(S m0)` and that the hypothesis `(Le n m0)` has been added to the context.

Sometimes it is interesting to have the equality `m = (S m0)` in the context to use it after. In that case we can use `inversion` that does not clear the equalities:

intros.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m : nat H : Le (S n) m ============================ P n m

inversion H.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m : nat H : Le (S n) m n0, m0 : nat H1 : Le n m0 H0 : n0 = n H2 : S m0 = m ============================ P n (S m0)

Example

Dependent inversion.

Let us consider the following goal:

Abort.
Goal forall n m (H: Le (S n) m), Q (S n) m H.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop ============================ forall (n m : nat) (H : Le (S n) m), Q (S n) m H

intros.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m : nat H : Le (S n) m ============================ Q (S n) m H

As `H` occurs in the goal, we may want to reason by cases on its structure and so, we would like inversion tactics to substitute `H` by the corresponding @term in constructor form. Neither `inversion` nor `inversion_clear` do such a substitution. To have such a behavior we use the dependent inversion tactics:

dependent inversion_clear H.
  1 goal P : nat -> nat -> Prop Q : forall n m : nat, Le n m -> Prop n, m, m0 : nat l : Le n m0 ============================ Q (S n) (S m0) (LeS n m0 l)

Note that `H` has been substituted by `(LeS n m0 l)` and `m` by `(S m0)`.

Example

Using inversion_sigma.

Let us consider the following inductive type of length-indexed lists, and a lemma about inverting equality of cons:

Require Import Coq.Logic.Eqdep_dec.
Inductive vec A : nat -> Type := | nil : vec A O | cons {n} (x : A) (xs : vec A n) : vec A (S n).
  vec is defined vec_rect is defined vec_ind is defined vec_rec is defined vec_sind is defined
Lemma invert_cons : forall A n x xs y ys, @cons A n x xs = @cons A n y ys -> xs = ys.
  1 goal ============================ forall (A : Type) (n : nat) (x : A) (xs : vec A n) (y : A) (ys : vec A n), cons A x xs = cons A y ys -> xs = ys
Proof.
intros A n x xs y ys H.
  1 goal A : Type n : nat x : A xs : vec A n y : A ys : vec A n H : cons A x xs = cons A y ys ============================ xs = ys

After performing inversion, we are left with an equality of existTs:

inversion H.
  1 goal A : Type n : nat x : A xs : vec A n y : A ys : vec A n H : cons A x xs = cons A y ys H1 : x = y H2 : existT (fun n : nat => vec A n) n xs = existT (fun n : nat => vec A n) n ys ============================ xs = ys

We can turn this equality into a usable form with inversion_sigma:

inversion_sigma.
  1 goal A : Type n : nat x : A xs : vec A n y : A ys : vec A n H : cons A x xs = cons A y ys H1 : x = y H2_ : n = n H2_0 : eq_rect n (fun n : nat => vec A n) xs n H2_ = ys ============================ xs = ys

To finish cleaning up the proof, we will need to use the fact that that all proofs of n = n for n a nat are eq_refl:

let H := match goal with H : n = n |- _ => H end in pose proof (Eqdep_dec.UIP_refl_nat _ H); subst H.
  1 goal A : Type n : nat x : A xs : vec A n y : A ys : vec A n H : cons A x xs = cons A y ys H1 : x = y H2_0 : eq_rect n (fun n : nat => vec A n) xs n eq_refl = ys ============================ xs = ys
simpl in *.
  1 goal A : Type n : nat x : A xs : vec A n y : A ys : vec A n H : cons A x xs = cons A y ys H1 : x = y H2_0 : xs = ys ============================ xs = ys

Finally, we can finish the proof:

assumption.
  No more goals.
Qed.

See also

`functional inversion`

Tactic fix ident natural

  This tactic is a primitive tactic to start a proof by induction. In general, it is easier to rely on higher-level induction tactics such as the ones described in `induction`.

  In the syntax of the tactic, the identifier `ident` is the name given to the induction hypothesis. The natural number `natural` tells on which premise of the current goal the induction acts, starting from 1, counting both dependent and non dependent products, but skipping local definitions. Especially, the current lemma must be composed of at least `natural` products.

  Like in a fix expression, the induction hypotheses have to be used on structurally smaller arguments. The verification that inductive proof arguments are correct is done only at the time of registering the lemma in the global environment. To know if the use of induction hypotheses is correct at some time of the interactive development of a proof, use the command `Guarded` (see Section Requesting information).

Variant fix ident natural with (ident binder+ [{struct ident}] : type)+

  This starts a proof by mutual induction. The statements to be simultaneously proved are respectively `forall binder ... binder, type`. The identifiers `ident` are the names of the induction hypotheses. The identifiers `ident` are the respective names of the premises on which the induction is performed in the statements to be simultaneously proved (if not given, the system tries to guess itself what they are).

Tactic cofix ident

  This tactic starts a proof by coinduction. The identifier `ident` is the name given to the coinduction hypothesis. Like in a cofix expression, the use of induction hypotheses have to guarded by a constructor. The verification that the use of co-inductive hypotheses is correct is done only at the time of registering the lemma in the global environment. To know if the use of coinduction hypotheses is correct at some time of the interactive development of a proof, use the command `Guarded` (see Section Requesting information).

Variant cofix ident with (ident binder+ : type)+

  This starts a proof by mutual coinduction. The statements to be simultaneously proved are respectively `forall binder ... binder, type` The identifiers `ident` are the names of the coinduction hypotheses.

## Equality and inductive sets

We describe in this section some special purpose tactics dealing with equality and inductive sets or types. These tactics use the equality `eq:forall (A:Type), A->A->Prop`, simply written with the infix symbol `=`.

Tactic decide equality

  This tactic solves a goal of the form `forall x y : R, {x = y} + {~ x = y}`, where `R` is an inductive type such that its constructors do not take proofs or functions as arguments, nor objects in dependent types. It solves goals of the form `{x = y} + {~ x = y}` as well.

Tactic compare term term

  This tactic compares two given objects `term` and `term` of an inductive datatype. If `G` is the current goal, it leaves the sub- goals `term =term -> G` and `~ term = term -> G`. The type of `term` and `term` must satisfy the same restrictions as in the tactic `decide equality`.

Tactic simplify_eq term

  Let `term` be the proof of a statement of conclusion `term = term`. If `term` and `term` are structurally different (in the sense described for the tactic `discriminate`), then the tactic `simplify_eq` behaves as `discriminate term`, otherwise it behaves as `injection term`.

Note

If some quantified hypothesis of the goal is named `ident`, then `simplify_eq ident` first introduces the hypothesis in the local context using `intros until ident`.

Variant simplify_eq natural

  This does the same thing as `intros until natural` then `simplify_eq ident` where `ident` is the identifier for the last introduced hypothesis.

Variant simplify_eq term with bindings

  This does the same as `simplify_eq term` but using the given bindings to instantiate parameters or hypotheses of `term`.

Variant esimplify_eq natural
Variant esimplify_eq term with bindings?

  This works the same as `simplify_eq` but if the type of `term`, or the type of the hypothesis referred to by `natural`, has uninstantiated parameters, these parameters are left as existential variables.

Variant simplify_eq

  If the current goal has form `t1 <> t2`, it behaves as `intro ident; simplify_eq ident`.

Tactic dependent rewrite -> ident

  This tactic applies to any goal. If `ident` has type `(existT B a b)=(existT B a' b')` in the local context (i.e. each `term` of the equality has a sigma type `{ a:A & (B a)}`) this tactic rewrites `a` into `a'` and `b` into `b'` in the current goal. This tactic works even if `B` is also a sigma type. This kind of equalities between dependent pairs may be derived by the `injection` and `inversion` tactics.

Variant dependent rewrite <- ident

  Analogous to `dependent rewrite ->` but uses the equality from right to left.

## Generation of induction principles with `Scheme`

Command Scheme ident :=? scheme_kind with ident :=? scheme_kind*

  > scheme_kind`::=`Equality for reference`````|`Induction​Minimality​Elimination​Case for reference Sort sort_family`` sort_family`::=`Set`````|`Prop`````|`SProp`````|`Type``

  A high-level tool for automatically generating (possibly mutual) induction principles for given types and sorts. Each `reference` is a different inductive type identifier belonging to the same package of mutual inductive definitions. The command generates the `ident`s as mutually recursive definitions. Each term `ident` proves a general principle of mutual induction for objects in type `reference`.

  `ident`

    The name of the scheme. If not provided, the scheme name will be determined automatically from the sorts involved.

  `Minimality for reference Sort sort_family`

    Defines a non-dependent elimination principle more natural for inductively defined relations.

  `Equality for reference`

    Tries to generate a Boolean equality and a proof of the decidability of the usual equality. If `reference` involves other inductive types, their equality has to be defined first.

Example

> Induction scheme for tree and forest.

> A mutual induction principle for tree and forest in sort `Set` can be defined using the command

> > Axiom A : Set.
> >   A is declared
> > Axiom B : Set.
> >   B is declared
> > Inductive tree : Set := node : A -> forest -> tree with forest : Set := leaf : B -> forest | cons : tree -> forest -> forest.
> >   tree, forest are defined tree_rect is defined tree_ind is defined tree_rec is defined tree_sind is defined forest_rect is defined forest_ind is defined forest_rec is defined forest_sind is defined
> > Scheme tree_forest_rec := Induction for tree Sort Set with forest_tree_rec := Induction for forest Sort Set.
> >   forest_tree_rec is defined tree_forest_rec is defined tree_forest_rec, forest_tree_rec are recursively defined

You may now look at the type of tree_forest_rec:

Check tree_forest_rec.
  tree_forest_rec : forall (P : tree -> Set) (P0 : forest -> Set), (forall (a : A) (f : forest), P0 f -> P (node a f)) -> (forall b : B, P0 (leaf b)) -> (forall t : tree, P t -> forall f1 : forest, P0 f1 -> P0 (cons t f1)) -> forall t : tree, P t

This principle involves two different predicates for trees andforests; it also has three premises each one corresponding to a constructor of one of the inductive definitions.

The principle `forest_tree_rec` shares exactly the same premises, only the conclusion now refers to the property of forests.

Example

Predicates odd and even on naturals.

Let odd and even be inductively defined as:

> Inductive odd : nat -> Prop := oddS : forall n: nat, even n -> odd (S n) with even : nat -> Prop := | evenO : even 0 | evenS : forall n: nat, odd n -> even (S n).
>   odd, even are defined odd_ind is defined odd_sind is defined even_ind is defined even_sind is defined

The following command generates a powerful elimination principle:

> Scheme odd_even := Minimality for odd Sort Prop with even_odd := Minimality for even Sort Prop.
>   even_odd is defined odd_even is defined odd_even, even_odd are recursively defined

The type of odd_even for instance will be:

Check odd_even.
  odd_even : forall P P0 : nat -> Prop, (forall n : nat, even n -> P0 n -> P (S n)) -> P0 0 -> (forall n : nat, odd n -> P n -> P0 (S n)) -> forall n : nat, odd n -> P n

The type of `even_odd` shares the same premises but the conclusion is `(n:nat)(even n)->(P0 n)`.

### Automatic declaration of schemes

Flag Elimination Schemes

  This flag enables automatic declaration of induction principles when defining a new inductive type. Defaults to on.

Flag Nonrecursive Elimination Schemes

  This flag enables automatic declaration of induction principles for types declared with the `Variant` and `Record` commands. Defaults to off.

Flag Case Analysis Schemes

  This flag governs the generation of case analysis lemmas for inductive types, i.e. corresponding to the pattern matching term alone and without fixpoint.

Flag Boolean Equality Schemes
Flag Decidable Equality Schemes

  These flags control the automatic declaration of those Boolean equalities (see the second variant of `Scheme`).

Warning

You have to be careful with these flags since Coq may now reject well-defined inductive types because it cannot compute a Boolean equality for them.

Flag Rewriting Schemes

  This flag governs generation of equality-related schemes such as congruence.

### Combined Scheme

Command Combined Scheme identdef from ident+,

  This command is a tool for combining induction principles generated by the `Scheme` command. Each `ident` is a different inductive principle that must belong to the same package of mutual inductive principle definitions. This command generates `identdef` as the conjunction of the principles: it is built from the common premises of the principles and concluded by the conjunction of their conclusions. In the case where all the inductive principles used are in sort `Prop`, the propositional conjunction `and` is used, otherwise the simple product `prod` is used instead.

Example

We can define the induction principles for trees and forests using:

Scheme tree_forest_ind := Induction for tree Sort Prop with forest_tree_ind := Induction for forest Sort Prop.
  forest_tree_ind is defined tree_forest_ind is defined tree_forest_ind, forest_tree_ind are recursively defined

Then we can build the combined induction principle which gives the conjunction of the conclusions of each individual principle:

Combined Scheme tree_forest_mutind from tree_forest_ind,forest_tree_ind.
  tree_forest_mutind is defined tree_forest_mutind is recursively defined

The type of tree_forest_mutind will be:

Check tree_forest_mutind.
  tree_forest_mutind : forall (P : tree -> Prop) (P0 : forest -> Prop), (forall (a : A) (f : forest), P0 f -> P (node a f)) -> (forall b : B, P0 (leaf b)) -> (forall t : tree, P t -> forall f1 : forest, P0 f1 -> P0 (cons t f1)) -> (forall t : tree, P t) /\ (forall f2 : forest, P0 f2)

Example

> We can also combine schemes at sort `Type`:

Scheme tree_forest_rect := Induction for tree Sort Type with forest_tree_rect := Induction for forest Sort Type.
  forest_tree_rect is defined tree_forest_rect is defined tree_forest_rect, forest_tree_rect are recursively defined

Combined Scheme tree_forest_mutrect from tree_forest_rect, forest_tree_rect.
  tree_forest_mutrect is defined tree_forest_mutrect is recursively defined

Check tree_forest_mutrect.
  tree_forest_mutrect : forall (P : tree -> Type) (P0 : forest -> Type), (forall (a : A) (f : forest), P0 f -> P (node a f)) -> (forall b : B, P0 (leaf b)) -> (forall t : tree, P t -> forall f1 : forest, P0 f1 -> P0 (cons t f1)) -> (forall t : tree, P t) * (forall f2 : forest, P0 f2)

See also

Generation of induction principles with Functional Scheme

## Generation of inversion principles with `Derive` `Inversion`

Command Derive Inversion ident with one_term Sort sort_family?

  Generates an inversion lemma for the `inversion ... using ...` tactic. `ident` is the name of the generated lemma. `one_term` should be in the form `qualid` or `(forall binder+, qualid term)` where `qualid` is the name of an inductive predicate and `binder+` binds the variables occurring in the term `term`. The lemma is generated for the sort `sort_family` corresponding to `one_term`. Applying the lemma is equivalent to inverting the instance with the `inversion` tactic.

Command Derive Inversion_clear ident with one_term Sort sort_family?

  When applied, it is equivalent to having inverted the instance with the tactic inversion replaced by the tactic `inversion_clear`.

Command Derive Dependent Inversion ident with one_term Sort sort_family

  When applied, it is equivalent to having inverted the instance with the tactic `dependent inversion`.

Command Derive Dependent Inversion_clear ident with one_term Sort sort_family

  When applied, it is equivalent to having inverted the instance with the tactic `dependent inversion_clear`.

Example

Consider the relation `Le` over natural numbers and the following parameter `P`:

Inductive Le : nat -> nat -> Set := | LeO : forall n: nat, Le 0 n | LeS : forall n m: nat, Le n m -> Le (S n) (S m).
  Le is defined Le_rect is defined Le_ind is defined Le_rec is defined Le_sind is defined
Parameter P : nat -> nat -> Prop.
  P is declared

To generate the inversion lemma for the instance `(Le (S n) m)` and the sort `Prop`, we do:

Derive Inversion_clear leminv with (forall n m: nat, Le (S n) m) Sort Prop.
  leminv is defined
Check leminv.
  leminv : forall (n m : nat) (P : nat -> nat -> Prop), (forall m0 : nat, Le n m0 -> P n (S m0)) -> Le (S n) m -> P n m

Then we can use the proven inversion lemma:

Goal forall (n m : nat) (H : Le (S n) m), P n m.
  1 goal ============================ forall n m : nat, Le (S n) m -> P n m
intros.
  1 goal n, m : nat H : Le (S n) m ============================ P n m

Show.
  1 goal n, m : nat H : Le (S n) m ============================ P n m
inversion H using leminv.
  1 goal n, m : nat H : Le (S n) m ============================ forall m0 : nat, Le n m0 -> P n (S m0)

## Examples of dependent destruction / dependent induction

The tactics `dependent induction` and `dependent destruction` are another solution for inverting inductive predicate instances and potentially doing induction at the same time. It is based on the `BasicElim` tactic of Conor McBride which works by abstracting each argument of an inductive instance by a variable and constraining it by equalities afterwards. This way, the usual induction and destruct tactics can be applied to the abstracted instance and after simplification of the equalities we get the expected goals.

The abstracting tactic is called generalize_eqs and it takes as argument a hypothesis to generalize. It uses the JMeq datatype defined in Coq.Logic.JMeq, hence we need to require it before. For example, revisiting the first example of the inversion documentation:

Require Import Coq.Logic.JMeq.
Inductive Le : nat -> nat -> Set := | LeO : forall n: nat, Le 0 n | LeS : forall n m: nat, Le n m -> Le (S n) (S m).
  Le is defined Le_rect is defined Le_ind is defined Le_rec is defined Le_sind is defined
Parameter P : nat -> nat -> Prop.
  P is declared
Goal forall n m: nat, Le (S n) m -> P n m.
  1 goal ============================ forall n m : nat, Le (S n) m -> P n m
intros n m H.
  1 goal n, m : nat H : Le (S n) m ============================ P n m

generalize_eqs H.
  1 goal n, m, gen_x : nat H : Le gen_x m ============================ gen_x = S n -> P n m

The index `S n` gets abstracted by a variable here, but a corresponding equality is added under the abstract instance so that no information is actually lost. The goal is now almost amenable to do induction or case analysis. One should indeed first move `n` into the goal to strengthen it before doing induction, or `n` will be fixed in the inductive hypotheses (this does not matter for case analysis). As a rule of thumb, all the variables that appear inside constructors in the indices of the hypothesis should be generalized. This is exactly what the `generalize_eqs_vars` variant does:

generalize_eqs_vars H.
induction H.
  2 goals n, n0 : nat ============================ 0 = S n -> P n n0 goal 2 is: S n0 = S n -> P n (S m)

As the hypothesis itself did not appear in the goal, we did not need to use an heterogeneous equality to relate the new hypothesis to the old one (which just disappeared here). However, the tactic works just as well in this case, e.g.:

Require Import Coq.Program.Equality.

Parameter Q : forall (n m : nat), Le n m -> Prop.
  Q is declared
Goal forall n m (p : Le (S n) m), Q (S n) m p.
  1 goal ============================ forall (n m : nat) (p : Le (S n) m), Q (S n) m p

intros n m p.
  1 goal n, m : nat p : Le (S n) m ============================ Q (S n) m p
generalize_eqs_vars p.
  1 goal m, gen_x : nat p : Le gen_x m ============================ forall (n : nat) (p0 : Le (S n) m), gen_x = S n -> p ~= p0 -> Q (S n) m p0

One drawback of this approach is that in the branches one will have to substitute the equalities back into the instance to get the right assumptions. Sometimes injection of constructors will also be needed to recover the needed equalities. Also, some subgoals should be directly solved because of inconsistent contexts arising from the constraints on indexes. The nice thing is that we can make a tactic based on discriminate, injection and variants of substitution to automatically do such simplifications (which may involve the axiom K). This is what the `simplify_dep_elim` tactic from `Coq.Program.Equality` does. For example, we might simplify the previous goals considerably:

induction p ; simplify_dep_elim.
  1 goal n, m : nat p : Le n m IHp : forall (n0 : nat) (p0 : Le (S n0) m), n = S n0 -> p ~= p0 -> Q (S n0) m p0 ============================ Q (S n) (S m) (LeS n m p)

The higher-order tactic `do_depind` defined in `Coq.Program.Equality` takes a tactic and combines the building blocks we have seen with it: generalizing by equalities calling the given tactic with the generalized induction hypothesis as argument and cleaning the subgoals with respect to equalities. Its most important instantiations are `dependent induction` and `dependent destruction` that do induction or simply case analysis on the generalized hypothesis. For example we can redo what we’ve done manually with dependent destruction:

Lemma ex : forall n m: nat, Le (S n) m -> P n m.
  1 goal ============================ forall n m : nat, Le (S n) m -> P n m

intros n m H.
  1 goal n, m : nat H : Le (S n) m ============================ P n m

dependent destruction H.
  1 goal n, m : nat H : Le n m ============================ P n (S m)

This gives essentially the same result as inversion. Now if the destructed hypothesis actually appeared in the goal, the tactic would still be able to invert it, contrary to dependent inversion. Consider the following example on vectors:

Set Implicit Arguments.

Parameter A : Set.
  A is declared

Inductive vector : nat -> Type := | vnil : vector 0 | vcons : A -> forall n, vector n -> vector (S n).
  vector is defined vector_rect is defined vector_ind is defined vector_rec is defined vector_sind is defined

Goal forall n, forall v : vector (S n), exists v' : vector n, exists a : A, v = vcons a v'.
  1 goal ============================ forall (n : nat) (v : vector (S n)), exists (v' : vector n) (a : A), v = vcons a v'

intros n v.
  1 goal n : nat v : vector (S n) ============================ exists (v' : vector n) (a : A), v = vcons a v'

dependent destruction v.
  1 goal n : nat a : A v : vector n ============================ exists (v' : vector n) (a0 : A), vcons a v = vcons a0 v'

In this case, the `v` variable can be replaced in the goal by the generalized hypothesis only when it has a type of the form `vector (S n)`, that is only in the second case of the destruct. The first one is dismissed because `S n <> 0`.

### A larger example

Let’s see how the technique works with induction on inductive predicates on a real example. We will develop an example application to the theory of simply-typed lambda-calculus formalized in a dependently-typed style:

Inductive type : Type := | base : type | arrow : type -> type -> type.
  type is defined type_rect is defined type_ind is defined type_rec is defined type_sind is defined

Notation " t --> t' " := (arrow t t') (at level 20, t' at next level).

Inductive ctx : Type := | empty : ctx | snoc : ctx -> type -> ctx.
  ctx is defined ctx_rect is defined ctx_ind is defined ctx_rec is defined ctx_sind is defined

Notation " G , tau " := (snoc G tau) (at level 20, tau at next level).

Fixpoint conc (G D : ctx) : ctx := match D with | empty => G | snoc D' x => snoc (conc G D') x end.
  conc is defined conc is recursively defined (guarded on 2nd argument)

Notation " G ; D " := (conc G D) (at level 20).

Inductive term : ctx -> type -> Type := | ax : forall G tau, term (G, tau) tau | weak : forall G tau, term G tau -> forall tau', term (G, tau') tau | abs : forall G tau tau', term (G , tau) tau' -> term G (tau --> tau') | app : forall G tau tau', term G (tau --> tau') -> term G tau -> term G tau'.
  term is defined term_rect is defined term_ind is defined term_rec is defined term_sind is defined

We have defined types and contexts which are snoc-lists of types. We also have a `conc` operation that concatenates two contexts. The `term` datatype represents in fact the possible typing derivations of the calculus, which are isomorphic to the well-typed terms, hence the name. A term is either an application of:

- the axiom rule to type a reference to the first variable in a context

- the weakening rule to type an object in a larger context

- the abstraction or lambda rule to type a function

- the application to type an application of a function to an argument

Once we have this datatype we want to do proofs on it, like weakening:

Lemma weakening : forall G D tau, term (G ; D) tau -> forall tau', term (G , tau' ; D) tau.
  1 goal ============================ forall (G D : ctx) (tau : type), term (G; D) tau -> forall tau' : type, term ((G, tau'); D) tau

The problem here is that we can’t just use induction on the typing derivation because it will forget about the `G ; D` constraint appearing in the instance. A solution would be to rewrite the goal as:

Lemma weakening' : forall G' tau, term G' tau -> forall G D, (G ; D) = G' -> forall tau', term (G, tau' ; D) tau.
  1 goal ============================ forall (G' : ctx) (tau : type), term G' tau -> forall G D : ctx, G; D = G' -> forall tau' : type, term ((G, tau'); D) tau

With this proper separation of the index from the instance and the right induction loading (putting `G` and `D` after the inducted-on hypothesis), the proof will go through, but it is a very tedious process. One is also forced to make a wrapper lemma to get back the more natural statement. The `dependent induction` tactic alleviates this trouble by doing all of this plumbing of generalizing and substituting back automatically. Indeed we can simply write:

Require Import Coq.Program.Tactics.
Require Import Coq.Program.Equality.

Lemma weakening : forall G D tau, term (G ; D) tau -> forall tau', term (G , tau' ; D) tau.
  1 goal ============================ forall (G D : ctx) (tau : type), term (G; D) tau -> forall tau' : type, term ((G, tau'); D) tau

Proof with simpl in * ; simpl_depind ; auto.

intros G D tau H. dependent induction H generalizing G D ; intros.
  1 goal G, D : ctx tau : type H : term (G; D) tau ============================ forall tau' : type, term ((G, tau'); D) tau 4 goals G0 : ctx tau : type G, D : ctx x : G0, tau = G; D tau' : type ============================ term ((G, tau'); D) tau goal 2 is: term ((G, tau'0); D) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau'

This call to dependent induction has an additional arguments which is a list of variables appearing in the instance that should be generalized in the goal, so that they can vary in the induction hypotheses. By default, all variables appearing inside constructors (except in a parameter position) of the instantiated hypothesis will be generalized automatically but one can always give the list explicitly.

Show.
  4 goals G0 : ctx tau : type G, D : ctx x : G0, tau = G; D tau' : type ============================ term ((G, tau'); D) tau goal 2 is: term ((G, tau'0); D) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau'

The `simpl_depind` tactic includes an automatic tactic that tries to simplify equalities appearing at the beginning of induction hypotheses, generally using trivial applications of `reflexivity`. In cases where the equality is not between constructor forms though, one must help the automation by giving some arguments, using the `specialize` tactic for example.

destruct D... apply weak; apply ax. apply ax.
  5 goals G0 : ctx tau, tau' : type ============================ term ((G0, tau), tau') tau goal 2 is: term (((G, tau'); D), t) t goal 3 is: term ((G, tau'0); D) tau goal 4 is: term ((G, tau'0); D) (tau --> tau') goal 5 is: term ((G, tau'0); D) tau' 4 goals G, D : ctx t, tau' : type ============================ term (((G, tau'); D), t) t goal 2 is: term ((G, tau'0); D) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau' 3 goals G0 : ctx tau : type H : term G0 tau tau' : type IHterm : forall G D : ctx, G0 = G; D -> forall tau' : type, term ((G, tau'); D) tau G, D : ctx x : G0, tau' = G; D tau'0 : type ============================ term ((G, tau'0); D) tau goal 2 is: term ((G, tau'0); D) (tau --> tau') goal 3 is: term ((G, tau'0); D) tau'

destruct D...
  4 goals G0 : ctx tau : type H : term G0 tau tau' : type IHterm : forall G D : ctx, G0 = G; D -> forall tau' : type, term ((G, tau'); D) tau tau'0 : type ============================ term ((G0, tau'), tau'0) tau goal 2 is: term (((G, tau'0); D), t) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau'

Show.
  4 goals G0 : ctx tau : type H : term G0 tau tau' : type IHterm : forall G D : ctx, G0 = G; D -> forall tau' : type, term ((G, tau'); D) tau tau'0 : type ============================ term ((G0, tau'), tau'0) tau goal 2 is: term (((G, tau'0); D), t) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau'

specialize (IHterm G0 empty eq_refl).
  4 goals G0 : ctx tau : type H : term G0 tau tau' : type IHterm : forall tau' : type, term ((G0, tau'); empty) tau tau'0 : type ============================ term ((G0, tau'), tau'0) tau goal 2 is: term (((G, tau'0); D), t) tau goal 3 is: term ((G, tau'0); D) (tau --> tau') goal 4 is: term ((G, tau'0); D) tau'

Once the induction hypothesis has been narrowed to the right equality, it can be used directly.

apply weak, IHterm.
  3 goals tau : type G, D : ctx IHterm : forall G0 D0 : ctx, G; D = G0; D0 -> forall tau' : type, term ((G0, tau'); D0) tau H : term (G; D) tau t, tau'0 : type ============================ term (((G, tau'0); D), t) tau goal 2 is: term ((G, tau'0); D) (tau --> tau') goal 3 is: term ((G, tau'0); D) tau'

Now concluding this subgoal is easy.

constructor; apply IHterm; reflexivity.
  2 goals G, D : ctx tau, tau' : type H : term ((G; D), tau) tau' IHterm : forall G0 D0 : ctx, (G; D), tau = G0; D0 -> forall tau'0 : type, term ((G0, tau'0); D0) tau' tau'0 : type ============================ term ((G, tau'0); D) (tau --> tau') goal 2 is: term ((G, tau'0); D) tau'

1

  Reminder: opaque constants will not be expanded by δ reductions.

Other versions v: 8.14.1

Versions
  dev
  stable
  v8.14
  8.13
  8.12
  8.11
  8.10
  8.9
  8.8
  8.7
  8.6
  8.5
  8.4
  8.3
  8.2
  8.1
  8.0

Downloads
  PDF