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 nth 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 nth 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 hadds hypothesisα = βwithe : α, x : β;h_generalize Hx : e == x with _chooses automatically chooses the name of assumptionα = β;h_generalize! Hx : e == xrevertsHx;- when
Hxis omitted, assumptionHx : e == xis 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 anexampledeclarationextract_goal my_decl: formats the statement as alemmaordefdeclaration calledmy_declextract_goal with i j k:only use local constantsi,j,kin 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.