Similar to constructor
, but does not reorder goals.
Multiple subst
. substs x y z
is the same as subst x, subst y, subst z
.
swap n
will move the n
th goal to the front.
swap
defaults to swap 2
, and so interchanges the first and second goals.
See also tactic.interactive.rotate
, which moves the first n
goals to the back.
rotate
moves the first goal to the back. rotate n
will do this n
times.
See also tactic.interactive.swap
, which moves the n
th goal to the front.
Clear all hypotheses starting with _
, like _match
and _let_match
.
Acts like have
, but removes a hypothesis with the same name as
this one. For example if the state is h : p ⊢ goal
and f : p → q
,
then after replace h := f h
the goal will be h : q ⊢ goal
,
where have h := f h
would result in the state h : p, h : q ⊢ goal
.
This can be used to simulate the specialize
and apply at
tactics
of Coq.
Make every proposition in the context decidable.
classical!
does this more aggressively, such that even if a decidable instance is already
available for a specific proposition, the noncomputable one will be used instead.
Like generalize
but also considers assumptions
specified by the user. The user can also specify to
omit the goal.
refine_struct { .. }
acts like refine
but works only with structure instance
literals. It creates a goal for each missing field and tags it with the name of the
field so that have_field
can be used to generically refer to the field currently
being refined.
As an example, we can use refine_struct
to automate the construction of semigroup
instances:
refine_struct ( { .. } : semigroup α ),
-- case semigroup, mul
-- α : Type u,
-- ⊢ α → α → α
-- case semigroup, mul_assoc
-- α : Type u,
-- ⊢ ∀ (a b c : α), a * b * c = a * (b * c)
have_field
, used after refine_struct _
, poses field
as a local constant
with the type of the field of the current goal:
refine_struct ({ .. } : semigroup α),
{ have_field, ... },
{ have_field, ... },
behaves like
refine_struct ({ .. } : semigroup α),
{ have field := @semigroup.mul, ... },
{ have field := @semigroup.mul_assoc, ... },
apply_rules hs with attrs n
applies the list of lemmas hs
and all lemmas tagged with an
attribute from the list attrs
, as well as the assumption
tactic on the
first goal and the resulting subgoals, iteratively, at most n
times.
n
is optional, equal to 50 by default.
You can pass an apply_cfg
option argument as apply_rules hs n opt
.
(A typical usage would be with apply_rules hs n { md := reducible }
,
which asks apply_rules
to not unfold semireducible
definitions (i.e. most)
when checking if a lemma matches the goal.)
For instance:
@[user_attribute]
meta def mono_rules : user_attribute :=
{ name := `mono_rules,
descr := "lemmas usable to prove monotonicity" }
attribute [mono_rules] add_le_add mul_le_mul_of_nonneg_right
lemma my_test {a b c d e : real} (h1 : a ≤ b) (h2 : c ≤ d) (h3 : 0 ≤ e) :
a + c * e + a + c + 0 ≤ b + d * e + b + d + e :=
-- any of the following lines solve the goal:
add_le_add (add_le_add (add_le_add (add_le_add h1 (mul_le_mul_of_nonneg_right h2 h3)) h1 ) h2) h3
by apply_rules [add_le_add, mul_le_mul_of_nonneg_right]
by apply_rules with mono_rules
by apply_rules [add_le_add] with mono_rules
```
h_generalize Hx : e == x
matches on cast _ e
in the goal and replaces it with
x
. It also adds Hx : e == x
as an assumption. If cast _ e
appears multiple
times (not necessarily with the same proof), they are all replaced by x
. cast
eq.mp
, eq.mpr
, eq.subst
, eq.substr
, eq.rec
and eq.rec_on
are all treated
as casts.
h_generalize Hx : e == x with h
adds hypothesisα = β
withe : α, x : β
;h_generalize Hx : e == x with _
chooses automatically chooses the name of assumptionα = β
;h_generalize! Hx : e == x
revertsHx
;- when
Hx
is omitted, assumptionHx : e == x
is not added.
guard_target' t
fails if the target of the main goal is not definitionally equal to t
.
We use this tactic for writing tests.
The difference with guard_target
is that this uses definitional equality instead of
alpha-equivalence.
Similar to existsi
. use x
will instantiate the first term of an ∃
or Σ
goal with x
. It
will then try to close the new goal using trivial'
, or try to simplify it by applying
exists_prop
. Unlike existsi
, x
is elaborated with respect to the expected type.
use
will alternatively take a list of terms [x0, ..., xn]
.
use
will work with constructors of arbitrary inductive types.
Examples:
example (α : Type) : ∃ S : set α, S = S :=
by use ∅
example : ∃ x : ℤ, x = x :=
by use 42
example : ∃ n > 0, n = n :=
begin
use 1,
-- goal is now 1 > 0 ∧ 1 = 1, whereas it would be ∃ (H : 1 > 0), 1 = 1 after existsi 1.
exact ⟨zero_lt_one, rfl⟩,
end
example : ∃ a b c : ℤ, a + b + c = 6 :=
by use [1, 2, 3]
example : ∃ p : ℤ × ℤ, p.1 = 1 :=
by use ⟨1, 42⟩
example : Σ x y : ℤ, (ℤ × ℤ) × ℤ :=
by use [1, 2, 3, 4, 5]
inductive foo
| mk : ℕ → bool × ℕ → ℕ → foo
example : foo :=
by use [100, tt, 4, 3]
```
clear_aux_decl
clears every aux_decl
in the local context for the current goal.
This includes the induction hypothesis when using the equation compiler and
_let_match
and _fun_match
.
It is useful when using a tactic such as finish
, simp *
or subst
that may use these
auxiliary declarations, and produce an error saying the recursion is not well founded.
example (n m : ℕ) (h₁ : n = m) (h₂ : ∃ a : ℕ, a = n ∧ a = m) : 2 * m = 2 * n :=
let ⟨a, ha⟩ := h₂ in
begin
clear_aux_decl, -- subst will fail without this line
subst h₁
end
example (x y : ℕ) (h₁ : ∃ n : ℕ, n * 1 = 2) (h₂ : 1 + 1 = 2 → x * 1 = y) : x = y :=
let ⟨n, hn⟩ := h₁ in
begin
clear_aux_decl, -- finish produces an error without this line
finish
end
```
The logic of change x with y at l
fails when there are dependencies.
change'
mimics the behavior of change
, except in the case of change x with y at l
.
In this case, it will correctly replace occurences of x
with y
at all possible hypotheses
in l
. As long as x
and y
are defeq, it should never fail.
set a := t with h
is a variant of let a := t
. It adds the hypothesis h : a = t
to
the local context and replaces t
with a
everywhere it can.
set a := t with ←h
will add h : t = a
instead.
set! a := t with h
does not do any replacing.
example (x : ℕ) (h : x = 3) : x + x + x = 9 :=
begin
set y := x with ←h_xy,
/-
x : ℕ,
y : ℕ := x,
h_xy : x = y,
h : y = 3
⊢ y + y + y = 9
-/
end
clear_except h₀ h₁
deletes all the assumptions it can except for h₀
and h₁
.
Format the current goal as a stand-alone example. Useful for testing tactics or creating minimal working examples.
extract_goal
: formats the statement as anexample
declarationextract_goal my_decl
: formats the statement as alemma
ordef
declaration calledmy_decl
extract_goal with i j k:
only use local constantsi
,j
,k
in the declaration
Examples:
example (i j k : ℕ) (h₀ : i ≤ j) (h₁ : j ≤ k) : i ≤ k :=
begin
extract_goal,
-- prints:
-- example (i j k : ℕ) (h₀ : i ≤ j) (h₁ : j ≤ k) : i ≤ k :=
-- begin
-- admit,
-- end
extract_goal my_lemma
-- prints:
-- lemma my_lemma (i j k : ℕ) (h₀ : i ≤ j) (h₁ : j ≤ k) : i ≤ k :=
-- begin
-- admit,
-- end
end
example {i j k x y z w p q r m n : ℕ} (h₀ : i ≤ j) (h₁ : j ≤ k) (h₁ : k ≤ p) (h₁ : p ≤ q) : i ≤ k :=
begin
extract_goal my_lemma,
-- prints:
-- lemma my_lemma {i j k x y z w p q r m n : ℕ}
-- (h₀ : i ≤ j)
-- (h₁ : j ≤ k)
-- (h₁ : k ≤ p)
-- (h₁ : p ≤ q) :
-- i ≤ k :=
-- begin
-- admit,
-- end
extract_goal my_lemma with i j k
-- prints:
-- lemma my_lemma {p i j k : ℕ}
-- (h₀ : i ≤ j)
-- (h₁ : j ≤ k)
-- (h₁ : k ≤ p) :
-- i ≤ k :=
-- begin
-- admit,
-- end
end
example : true :=
begin
let n := 0,
have m : ℕ, admit,
have k : fin n, admit,
have : n + m + k.1 = 0, extract_goal,
-- prints:
-- example (m : ℕ) : let n : ℕ := 0 in ∀ (k : fin n), n + m + k.val = 0 :=
-- begin
-- intros n k,
-- admit,
-- end
end
```
inhabit α
tries to derive a nonempty α
instance and then upgrades this
to an inhabited α
instance.
If the target is a Prop
, this is done constructively;
otherwise, it uses classical.choice
.
revert_deps n₁ n₂ ...
reverts all the hypotheses that depend on one of n₁, n₂, ...
It does not revert n₁, n₂, ...
themselves (unless they depend on another nᵢ
).
revert_after n
reverts all the hypotheses after n
.
Reverts all local constants on which the target depends (recursively).
clear_value n₁ n₂ ...
clears the bodies of the local definitions n₁, n₂ ...
, changing them
into regular hypotheses. A hypothesis n : α := t
is changed to n : α
.
generalize' : e = x
replaces all occurrences of e
in the target with a new hypothesis x
of
the same type.
generalize' h : e = x
in addition registers the hypothesis h : e = x
.
generalize'
is similar to generalize
. The difference is that generalize' : e = x
also
succeeds when e
does not occur in the goal. It is similar to set
, but the resulting hypothesis
x
is not a local definition.
If the expression q
is a local variable with type x = t
or t = x
, where x
is a local
constant, tactic.interactive.subst' q
substitutes x
by t
everywhere in the main goal and
then clears q
.
If q
is another local variable, then we find a local constant with type q = t
or t = q
and
substitute t
for q
.
Like tactic.interactive.subst
, but fails with a nicer error message if the substituted variable is
a local definition. It is trickier to fix this in core, since tactic.is_local_def
is in mathlib.