The convert tactic. #
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.
Configuration for the convert family of tactics.
This is Congr!.Config with different, less aggressive, defaults.
To elaborate config options for convert, use Convert.elabConfig which chooses
between Convert.CheapConfig and Convert.ExpensiveConfig based on other flags.
Instances For
Internal elaborator for Convert.CheapConfig: use Convert.elabConfig instead.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A configuration option that makes convert do the sorts of aggressive unfoldings that congr
does while also similarly preventing convert from considering partial applications or congruences
between different functions being applied.
Note that convert (config := .unfoldSameFun) and convert! (config := .unfoldSameFun)
currently do the same thing since .unfoldSameFun runs at default transparency always.
This may change in the future, if convert! affects other options too.
Equations
- Convert.CheapConfig.unfoldSameFun = { toConfig := Congr!.Config.unfoldSameFun }
Instances For
Configuration for the convert! family of tactics.
This is Convert.CheapConfig (used by convert without exclamation mark) with different,
more aggressive, defaults.
To elaborate config options for convert, use Convert.elabConfig which chooses
between Convert.CheapConfig and Convert.ExpensiveConfig based on other flags.
We separate out the two structures to allow the user to explicitly set options in the call, so for
example the following call runs at .instances transparency.
convert! (postTransparency := .instances)
Instances For
Internal elaborator for Convert.ExpensiveConfig: use Convert.elabConfig instead.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A configuration option that makes convert! do the sorts of aggressive unfoldings that congr
does while also similarly preventing convert! from considering partial applications or congruences
between different functions being applied.
Note that convert (config := .unfoldSameFun) and convert! (config := .unfoldSameFun)
currently do the same thing since .unfoldSameFun runs at default transparency always.
This may change in the future, if convert! affects other options too.
Equations
Instances For
Configuration elaborator for the convert/convert! family of tactics.
If expensive is true, we're elaborating for convert!, and will configure to run at default
transparency (unless explicitly overridden by the user saying e.g. (transparency := .instances).)
Equations
- One or more equations did not get rendered due to their size.
Instances For
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 symm = 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
Replaces the type of the local declaration fvarId with typeNew,
using Lean.MVarId.congrN! to prove that the old type of fvarId is equal to typeNew.
Uses Lean.MVarId.replaceLocalDecl to replace the type.
Returns the new goal along with the side goals generated by congrN!.
With symm = true, reverses the equality,
changing the goal to prove typeNew is equal to typeOld.
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
convert e, where the term e is inferred to have type t, replaces the main goal ⊢ t' with new
goals for proving the equality t' = t using congruence. The goals are created like congr! would.
Like refine e, any holes (?_ or ?x) in e that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
See also convert_to t, where t specifies the expected type, instead of a proof term of type t.
In other words, convert_to t works like convert (?_ : t). Both tactics use the same options.
convert! euses default transparency, rather than reducible, when solving side goals.convert ← ecreates equality goals in the opposite direction (with the goal type on the right).convert e using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1)ande : Prime (2 * n + 1), thenconvert e using 2results in one goal,⊢ n + n = 2 * n, andconvert e using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. By default, the depth is unlimited.convert e with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert (config := cfg) euses the configuration options incfgto control the congruence rules (seeCongr!.Config).
Examples:
-- `convert using` controls the depth of congruence.
example {n : ℕ} (e : Prime (2 * n + 1)) :
Prime (n + n + 1) := by
convert e using 2
-- One goal: ⊢ n + n = 2 * n
ring
-- `convert` can fail where `exact` succeeds.
def p (n : ℕ) := True
example (h : p 0) : p 1 := by
fail_if_success
convert h -- fails, left-over goal 1 = 0
done
exact h -- succeeds
-- `convert with` names introduced variables.
example (p q : Nat → Prop) (h : ∀ ε > 0, p ε) :
∀ ε > 0, q ε := by
convert h using 2 with ε hε
-- Goal now looks like:
-- hε : ε > 0
-- ⊢ q ε ↔ p ε
sorry
Equations
- One or more equations did not get rendered due to their size.
Instances For
convert e, where the term e is inferred to have type t, replaces the main goal ⊢ t' with new
goals for proving the equality t' = t using congruence. The goals are created like congr! would.
Like refine e, any holes (?_ or ?x) in e that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
See also convert_to t, where t specifies the expected type, instead of a proof term of type t.
In other words, convert_to t works like convert (?_ : t). Both tactics use the same options.
convert! euses default transparency, rather than reducible, when solving side goals.convert ← ecreates equality goals in the opposite direction (with the goal type on the right).convert e using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1)ande : Prime (2 * n + 1), thenconvert e using 2results in one goal,⊢ n + n = 2 * n, andconvert e using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. By default, the depth is unlimited.convert e with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert (config := cfg) euses the configuration options incfgto control the congruence rules (seeCongr!.Config).
Examples:
-- `convert using` controls the depth of congruence.
example {n : ℕ} (e : Prime (2 * n + 1)) :
Prime (n + n + 1) := by
convert e using 2
-- One goal: ⊢ n + n = 2 * n
ring
-- `convert` can fail where `exact` succeeds.
def p (n : ℕ) := True
example (h : p 0) : p 1 := by
fail_if_success
convert h -- fails, left-over goal 1 = 0
done
exact h -- succeeds
-- `convert with` names introduced variables.
example (p q : Nat → Prop) (h : ∀ ε > 0, p ε) :
∀ ε > 0, q ε := by
convert h using 2 with ε hε
-- Goal now looks like:
-- hε : ε > 0
-- ⊢ q ε ↔ p ε
sorry
Equations
- One or more equations did not get rendered due to their size.
Instances For
Elaborates term ensuring the expected type, allowing stuck metavariables.
Returns stuck metavariables as additional goals.
Equations
- One or more equations did not get rendered due to their size.
Instances For
convert_to t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the
equality t' = t using congruence. The goals are created like congr! would.
Any remaining congruence goals come before the main goal.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
convert e, where e is a term of type t, uses e to close the new main goal. In other words,
convert e works like convert_to t; refine e. Both tactics use the same options.
convert_to! tuses default transparency, rather than reducible, when solving side goals.convert_to ty at hchanges the type of the local hypothesishtoty. If later local hypotheses or the goal depend onh, thenconvert_to t at hmay leave a copy ofh.convert_to ← tcreates equality goals in the opposite direction (with the original goal type on the right).convert_to t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1), thenconvert_to Prime (2 * n + 1) using 2results in one goal,⊢ n + n = 2 * n, andconvert_to Prime (2 * n + 1) using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. The default value fornis 1.convert_to t with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert_to (config := cfg) tuses the configuration options incfgto control the congruence rules (seeCongr!.Config).
Equations
- One or more equations did not get rendered due to their size.
Instances For
convert_to t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the
equality t' = t using congruence. The goals are created like congr! would.
Any remaining congruence goals come before the main goal.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
convert e, where e is a term of type t, uses e to close the new main goal. In other words,
convert e works like convert_to t; refine e. Both tactics use the same options.
convert_to! tuses default transparency, rather than reducible, when solving side goals.convert_to ty at hchanges the type of the local hypothesishtoty. If later local hypotheses or the goal depend onh, thenconvert_to t at hmay leave a copy ofh.convert_to ← tcreates equality goals in the opposite direction (with the original goal type on the right).convert_to t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1), thenconvert_to Prime (2 * n + 1) using 2results in one goal,⊢ n + n = 2 * n, andconvert_to Prime (2 * n + 1) using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. The default value fornis 1.convert_to t with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert_to (config := cfg) tuses the configuration options incfgto control the congruence rules (seeCongr!.Config).
Equations
- One or more equations did not get rendered due to their size.
Instances For
ac_change t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the equality
t' = t using congruence, then tries proving these goals by associativity and commutativity. The
goals are created like congr! would.
In other words, ac_change t is like convert_to t followed by ac_refl.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
ac_change! tuses default transparency, rather than reducible, when solving side goals.ac_change t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime ((a * b + 1) + c), thenac_change Prime ((1 + a * b) + c) using 2solves the side goals, andac_change Prime ((1 + a * b) + c) using 3(or more) results in two (impossible) goals⊢ 1 = a * band⊢ a * b = 1. The default value fornis 1.
Example:
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.
Instances For
ac_change t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the equality
t' = t using congruence, then tries proving these goals by associativity and commutativity. The
goals are created like congr! would.
In other words, ac_change t is like convert_to t followed by ac_refl.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
ac_change! tuses default transparency, rather than reducible, when solving side goals.ac_change t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime ((a * b + 1) + c), thenac_change Prime ((1 + a * b) + c) using 2solves the side goals, andac_change Prime ((1 + a * b) + c) using 3(or more) results in two (impossible) goals⊢ 1 = a * band⊢ a * b = 1. The default value fornis 1.
Example:
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.