Close the goal g
using Eq.mp v e
,
where v
is a metavariable asserting that the type of g
and e
are equal.
Then call MVarId.congrN!
(also using local hypotheses and reflexivity) on v
,
and return the resulting goals.
With sym = true
, reverses the equality in v
, and uses Eq.mpr v e
instead.
With depth = some n
, calls MVarId.congrN! n
instead, with n
as the max recursion depth.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The exact e
and refine e
tactics require a term e
whose type is
definitionally equal to the goal. convert e
is similar to refine e
,
but the type of e
is not required to exactly match the
goal. Instead, new goals are created for differences between the type
of e
and the goal using the same strategies as the congr!
tactic.
For example, in the proof state
n : ℕ,
e : Prime (2 * n + 1)
⊢ Prime (n + n + 1)
the tactic convert e using 2
will change the goal to
⊢ n + n = 2 * n
In this example, the new goal can be solved using ring
.
The using 2
indicates it should iterate the congruence algorithm up to two times,
where convert e
would use an unrestricted number of iterations and lead to two
impossible goals: ⊢ HAdd.hAdd = HMul.hMul
and ⊢ n = 2
.
A variant configuration is convert (config := .unfoldSameFun) e
, which only equates function
applications for the same function (while doing so at the higher default
transparency).
This gives the same goal of ⊢ n + n = 2 * n
without needing using 2
.
The convert
tactic applies congruence lemmas eagerly before reducing,
therefore it can fail in cases where exact
succeeds:
def p (n : ℕ) := True
example (h : p 0) : p 1 := by exact h -- succeeds
example (h : p 0) : p 1 := by convert h -- fails, with leftover goal `1 = 0`
Limiting the depth of recursion can help with this. For example, convert h using 1
will work
in this case.
The syntax convert ← e
will reverse the direction of the new goals
(producing ⊢ 2 * n = n + n
in this example).
Internally, convert e
works by creating a new goal asserting that
the goal equals the type of e
, then simplifying it using
congr!
. The syntax convert e using n
can be used to control the
depth of matching (like congr! n
). In the example, convert e using 1
would produce a new goal ⊢ n + n + 1 = 2 * n + 1
.
Refer to the congr!
tactic to understand the congruence operations. One of its many
features is that if x y : t
and an instance Subsingleton t
is in scope,
then any goals of the form x = y
are solved automatically.
Like congr!
, convert
takes an optional with
clause of rintro
patterns,
for example convert e using n with x y z
.
The convert
tactic also takes a configuration option, for example
convert (config := {transparency := .default}) h
These are passed to congr!
. See Congr!.Config
for options.
Equations
- One or more equations did not get rendered due to their size.
Instances For
convert_to g using n
attempts to change the current goal to g
, but unlike change
,
it will generate equality proof obligations using congr! n
to resolve discrepancies.
convert_to g
defaults to using congr! 1
.
convert_to
is similar to convert
, but convert_to
takes a type (the desired subgoal) while
convert
takes a proof term.
That is, convert_to g using n
is equivalent to convert (?_ : g) using n
.
The syntax for convert_to
is the same as for convert
, and it has variations such as
convert_to ← g
and convert_to (config := {transparency := .default}) g
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
ac_change g using n
is convert_to g using n
followed by ac_rfl
. It is useful for
rearranging/reassociating e.g. sums:
example (a b c d e f g N : ℕ) : (a + b) + (c + d) + (e + f) + g ≤ N := by
ac_change a + d + e + f + c + g + b ≤ _
-- ⊢ a + d + e + f + c + g + b ≤ N
Equations
- One or more equations did not get rendered due to their size.