11.Β The Conversion Tactic Mode
Inside a tactic block, one can use the keyword conv
to enter
conversion mode. This mode allows to travel inside assumptions and
goals, even inside function abstractions and dependent arrows, to apply rewriting or
simplifying steps.
11.1.Β Basic navigation and rewriting
As a first example, let us prove example
(a b c : Nat) : a * (b * c) = a * (c * b)
(examples in this file are somewhat artificial since
other tactics could finish them immediately). The naive
first attempt is to enter tactic mode and try rw [Nat.mul_comm]
. But this
transforms the goal into b * c * a = a * (c * b)
, after commuting the
very first multiplication appearing in the term. There are several
ways to fix this issue, and one way is to use a more precise tool:
the conversion mode. The following code block shows the current target
after each line.
#guard_msgs (drop all) in
example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Natβ’ a * (b * c) = a * (c * b)
a:Natb:Natc:Natβ’ b * c * a = a * (c * b)
example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Natβ’ a * (b * c) = a * (c * b)
a:Natb:Natc:Nat| a * (b * c) = a * (c * b)
a:Natb:Natc:Nat| a * (b * c)
a:Natb:Natc:Nat| aa:Natb:Natc:Nat| b * c
a:Natb:Natc:Nat| b * c
a:Natb:Natc:Nat| c * b
The above snippet shows three navigation commands:
-
lhs
navigates to the left-hand side of a relation (equality, in this case). There is also arhs
to navigate to the right-hand side. -
congr
creates as many targets as there are (nondependent and explicit) arguments to the current head function (here the head function is multiplication). -
rfl
closes target using reflexivity.
Once arrived at the relevant target, we can use rw
as in normal
tactic mode.
The second main reason to use conversion mode is to rewrite under
binders. Suppose we want to prove example
(fun x : Nat => 0 + x) = (fun x => x)
.
The naive first attempt is to enter tactic mode and try
rw [Nat.zero_add]
. But this fails with a frustrating
error: tactic 'rewrite' failed, did not find instance of the pattern in the target expression 0 + ?n β’ (fun x => 0 + x) = fun x => x
The solution is:
example : (fun x : Nat => 0 + x) = (fun x => x) := β’ (fun x => 0 + x) = fun x => x
| (fun x => 0 + x) = fun x => x
| fun x => 0 + x
x:Nat| 0 + x
x:Nat| x
where intro x
is the navigation command entering inside the fun
binder.
Note that this example is somewhat artificial, one could also do:
example : (fun x : Nat => 0 + x) = (fun x => x) := β’ (fun x => 0 + x) = fun x => x
x:Natβ’ 0 + x = x; All goals completed! π
or just
example : (fun x : Nat => 0 + x) = (fun x => x) := β’ (fun x => 0 + x) = fun x => x
All goals completed! π
conv
can also rewrite a hypothesis h
from the local context, using conv at
h
.
11.2.Β Pattern matching
Navigation using the above commands can be tedious. One can shortcut it using pattern matching as follows:
example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Natβ’ a * (b * c) = a * (c * b)
a:Natb:Natc:Nat| b * c
a:Natb:Natc:Nat| c * b
which is just syntax sugar for
example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Natβ’ a * (b * c) = a * (c * b)
a:Natb:Natc:Nat| a * (b * c) = a * (c * b)
a:Natb:Natc:Nat| b * c
a:Natb:Natc:Nat| c * b
Of course, wildcards are allowed:
11.3.Β Structuring conversion tactics
Curly brackets and .
can also be used in conv
mode to structure tactics:
11.4.Β Other tactics inside conversion mode
-
arg
i
enter thei
-th nondependent explicit argument of an application. -
args
is an alternative name forcongr
. -
simp
applies the simplifier to the current goal. It supports the same options available in regular tactic mode.def f (x : Nat) := if x > 0 then x + 1 else x + 2
example (g : Nat β Nat) (hβ : g x = x + 1) (hβ : x > 0) : g x = f x := x:Natg:Nat β Nathβ:g x = x + 1hβ:x > 0β’ g x = f x x:Natg:Nat β Nathβ:g x = x + 1hβ:x > 0| g x = f x x:Natg:Nat β Nathβ:g x = x + 1hβ:x > 0| f x x:Natg:Nat β Nathβ:g x = x + 1hβ:x > 0| x + 1 All goals completed! π
-
enter
[1, x, 2, y]
iteratearg
andintro
with the given arguments. -
done
fail if there are unsolved goals. -
trace_state
display the current tactic state. -
whnf
put term in weak head normal form. -
tactic
=> <tactic sequence>
go back to regular tactic mode. This is useful for discharging goals not supported byconv
mode, and applying custom congruence and extensionality lemmas.example (g : Nat β Nat β Nat) (hβ : β x, x β 0 β g x x = 1) (hβ : x β 0) : g x x + x = 1 + x := x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0β’ g x x + x = 1 + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x + x = 1 + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| 1x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0β’ x β 0 . x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| 1 . x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0β’ x β 0 All goals completed! π
-
apply
<term>
is syntax sugar fortactic
=> apply <term>
.example (g : Nat β Nat β Nat) (hβ : β x, x β 0 β g x x = 1) (hβ : x β 0) : g x x + x = 1 + x := x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0β’ g x x + x = 1 + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x + x = 1 + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x + x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| g x x x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| 1x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0β’ x β 0 . x:Natg:Nat β Nat β Nathβ:β (x : Nat), x β 0 β g x x = 1hβ:x β 0| 1 . All goals completed! π