The generalizes
tactic #
This module defines the tactic.generalizes'
tactic and its interactive version
tactic.interactive.generalizes
. These work like generalize
, but they can
generalize over multiple expressions at once. This is particularly handy when
there are dependencies between the expressions, in which case generalize
will
usually fail but generalizes
may succeed.
Implementation notes #
To generalize the target T
over expressions j₁ : J₁, ..., jₙ : Jₙ
, we first
create the new target type
T' = ∀ (k₁ : J₁) ... (kₙ : Jₙ) (k₁_eq : k₁ = j₁) ... (kₙ_eq : kₙ == jₙ), U
where U
is T
with any occurrences of the jᵢ
replaced by the corresponding
kᵢ
. Note that some of the kᵢ_eq
may be heterogeneous; this happens when
there are dependencies between the jᵢ
. The construction of T'
is performed
by generalizes.step1
and generalizes.step2
.
Having constructed T'
, we can assert
it and use it to construct a proof of
the original target by instantiating the binders with
This leaves us with a generalized goal. This construction is performed by
generalizes.step3
.
Generalizes the target over multiple expressions. For example, given the goal
you can use generalizes [n'_eq : nat.succ n = n', f'_eq : fin.succ f == f']
to
get
P : ∀ n, fin n → Prop
n : ℕ
f : fin n
n' : ℕ
n'_eq : n' = nat.succ n
f' : fin n'
f'_eq : f' == fin.succ f
⊢ P n' f'
The expressions must be given in dependency order, so
[f'_eq : fin.succ f == f', n'_eq : nat.succ n = n']
would fail since the type
of fin.succ f
is nat.succ n
.
You can choose to omit some or all of the generated equations. For the above
example, generalizes [nat.succ n = n', fin.succ f == f']
gets you
After generalization, the target type may no longer type check. generalizes
will then raise an error.