93
+ − 1
theory Tactical
99
+ − 2
imports Base FirstSteps
93
+ − 3
begin
+ − 4
+ − 5
chapter {* Tactical Reasoning\label{chp:tactical} *}
+ − 6
+ − 7
text {*
213
+ − 8
One of the main reason for descending to the ML-level of Isabelle is to be able to
105
+ − 9
implement automatic proof procedures. Such proof procedures usually lessen
+ − 10
considerably the burden of manual reasoning, for example, when introducing
+ − 11
new definitions. These proof procedures are centred around refining a goal
+ − 12
state using tactics. This is similar to the \isacommand{apply}-style
157
+ − 13
reasoning at the user-level, where goals are modified in a sequence of proof
105
+ − 14
steps until all of them are solved. However, there are also more structured
+ − 15
operations available on the ML-level that help with the handling of
+ − 16
variables and assumptions.
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 17
93
+ − 18
*}
+ − 19
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 20
section {* Basics of Reasoning with Tactics*}
93
+ − 21
+ − 22
text {*
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 23
To see how tactics work, let us first transcribe a simple \isacommand{apply}-style proof
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 24
into ML. Suppose the following proof.
93
+ − 25
*}
+ − 26
+ − 27
lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P"
+ − 28
apply(erule disjE)
+ − 29
apply(rule disjI2)
+ − 30
apply(assumption)
+ − 31
apply(rule disjI1)
+ − 32
apply(assumption)
+ − 33
done
+ − 34
+ − 35
text {*
+ − 36
This proof translates to the following ML-code.
+ − 37
+ − 38
@{ML_response_fake [display,gray]
+ − 39
"let
+ − 40
val ctxt = @{context}
+ − 41
val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"}
+ − 42
in
+ − 43
Goal.prove ctxt [\"P\", \"Q\"] [] goal
+ − 44
(fn _ =>
+ − 45
etac @{thm disjE} 1
+ − 46
THEN rtac @{thm disjI2} 1
+ − 47
THEN atac 1
+ − 48
THEN rtac @{thm disjI1} 1
+ − 49
THEN atac 1)
+ − 50
end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"}
+ − 51
+ − 52
To start the proof, the function @{ML "Goal.prove"}~@{text "ctxt xs As C
99
+ − 53
tac"} sets up a goal state for proving the goal @{text C}
+ − 54
(that is @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"} in the proof at hand) under the
+ − 55
assumptions @{text As} (happens to be empty) with the variables
93
+ − 56
@{text xs} that will be generalised once the goal is proved (in our case
+ − 57
@{text P} and @{text Q}). The @{text "tac"} is the tactic that proves the goal;
+ − 58
it can make use of the local assumptions (there are none in this example).
256
+ − 59
The tactics @{ML [index] etac}, @{ML [index] rtac} and @{ML [index] atac} in the code above correspond
241
+ − 60
roughly to @{text erule}, @{text rule} and @{text assumption}, respectively.
256
+ − 61
The operator @{ML [index] THEN} strings the tactics together.
93
+ − 62
+ − 63
\begin{readmore}
256
+ − 64
To learn more about the function @{ML [index] prove in Goal} see \isccite{sec:results}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 65
and the file @{ML_file "Pure/goal.ML"}. See @{ML_file
99
+ − 66
"Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic
+ − 67
tactics and tactic combinators; see also Chapters 3 and 4 in the old
162
+ − 68
Isabelle Reference Manual, and Chapter 3 in the Isabelle/Isar Implementation Manual.
93
+ − 69
\end{readmore}
+ − 70
120
+ − 71
Note that in the code above we use antiquotations for referencing the theorems. Many theorems
105
+ − 72
also have ML-bindings with the same name. Therefore, we could also just have
231
+ − 73
written @{ML "etac disjE 1"}, or in case where there is no ML-binding obtain
107
+ − 74
the theorem dynamically using the function @{ML thm}; for example
109
+ − 75
\mbox{@{ML "etac (thm \"disjE\") 1"}}. Both ways however are considered bad style!
107
+ − 76
The reason
105
+ − 77
is that the binding for @{ML disjE} can be re-assigned by the user and thus
+ − 78
one does not have complete control over which theorem is actually
+ − 79
applied. This problem is nicely prevented by using antiquotations, because
+ − 80
then the theorems are fixed statically at compile-time.
93
+ − 81
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 82
During the development of automatic proof procedures, you will often find it
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 83
necessary to test a tactic on examples. This can be conveniently
93
+ − 84
done with the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}.
+ − 85
Consider the following sequence of tactics
+ − 86
*}
+ − 87
+ − 88
ML{*val foo_tac =
+ − 89
(etac @{thm disjE} 1
+ − 90
THEN rtac @{thm disjI2} 1
+ − 91
THEN atac 1
+ − 92
THEN rtac @{thm disjI1} 1
+ − 93
THEN atac 1)*}
+ − 94
+ − 95
text {* and the Isabelle proof: *}
+ − 96
+ − 97
lemma "P \<or> Q \<Longrightarrow> Q \<or> P"
+ − 98
apply(tactic {* foo_tac *})
+ − 99
done
+ − 100
+ − 101
text {*
104
+ − 102
By using @{text "tactic \<verbopen> \<dots> \<verbclose>"} you can call from the
157
+ − 103
user-level of Isabelle the tactic @{ML foo_tac} or
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 104
any other function that returns a tactic.
93
+ − 105
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 106
The tactic @{ML foo_tac} is just a sequence of simple tactics stringed
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 107
together by @{ML THEN}. As can be seen, each simple tactic in @{ML foo_tac}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 108
has a hard-coded number that stands for the subgoal analysed by the
105
+ − 109
tactic (@{text "1"} stands for the first, or top-most, subgoal). This hard-coding
+ − 110
of goals is sometimes wanted, but usually it is not. To avoid the explicit numbering,
238
+ − 111
you can write
93
+ − 112
*}
+ − 113
+ − 114
ML{*val foo_tac' =
+ − 115
(etac @{thm disjE}
+ − 116
THEN' rtac @{thm disjI2}
+ − 117
THEN' atac
+ − 118
THEN' rtac @{thm disjI1}
238
+ − 119
THEN' atac)*}text_raw{*\label{tac:footacprime}*}
93
+ − 120
+ − 121
text {*
256
+ − 122
where @{ML [index] THEN'} is used instead of @{ML THEN}. With @{ML foo_tac'} you can give
213
+ − 123
the number for the subgoal explicitly when the tactic is
105
+ − 124
called. So in the next proof you can first discharge the second subgoal, and
109
+ − 125
subsequently the first.
93
+ − 126
*}
+ − 127
+ − 128
lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1"
+ − 129
and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2"
+ − 130
apply(tactic {* foo_tac' 2 *})
+ − 131
apply(tactic {* foo_tac' 1 *})
+ − 132
done
+ − 133
+ − 134
text {*
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 135
This kind of addressing is more difficult to achieve when the goal is
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 136
hard-coded inside the tactic. For most operators that combine tactics
105
+ − 137
(@{ML THEN} is only one such operator) a ``primed'' version exists.
99
+ − 138
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 139
The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 140
analysing goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 141
of this form, then these tactics return the error message:
99
+ − 142
+ − 143
\begin{isabelle}
+ − 144
@{text "*** empty result sequence -- proof command failed"}\\
+ − 145
@{text "*** At command \"apply\"."}
+ − 146
\end{isabelle}
+ − 147
241
+ − 148
This means they failed.\footnote{To be precise tactics do not produce this error
+ − 149
message, the it originates from the \isacommand{apply} wrapper.} The reason for this
+ − 150
error message is that tactics
109
+ − 151
are functions mapping a goal state to a (lazy) sequence of successor states.
+ − 152
Hence the type of a tactic is:
+ − 153
*}
93
+ − 154
109
+ − 155
ML{*type tactic = thm -> thm Seq.seq*}
93
+ − 156
109
+ − 157
text {*
+ − 158
By convention, if a tactic fails, then it should return the empty sequence.
+ − 159
Therefore, if you write your own tactics, they should not raise exceptions
+ − 160
willy-nilly; only in very grave failure situations should a tactic raise the
+ − 161
exception @{text THM}.
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 162
256
+ − 163
The simplest tactics are @{ML [index] no_tac} and @{ML [index] all_tac}. The first returns
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 164
the empty sequence and is defined as
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 165
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 166
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 167
ML{*fun no_tac thm = Seq.empty*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 168
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 169
text {*
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 170
which means @{ML no_tac} always fails. The second returns the given theorem wrapped
173
+ − 171
in a single member sequence; it is defined as
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 172
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 173
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 174
ML{*fun all_tac thm = Seq.single thm*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 175
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 176
text {*
109
+ − 177
which means @{ML all_tac} always succeeds, but also does not make any progress
+ − 178
with the proof.
93
+ − 179
109
+ − 180
The lazy list of possible successor goal states shows through at the user-level
99
+ − 181
of Isabelle when using the command \isacommand{back}. For instance in the
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 182
following proof there are two possibilities for how to apply
107
+ − 183
@{ML foo_tac'}: either using the first assumption or the second.
93
+ − 184
*}
+ − 185
+ − 186
lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P"
+ − 187
apply(tactic {* foo_tac' 1 *})
+ − 188
back
+ − 189
done
+ − 190
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 191
93
+ − 192
text {*
99
+ − 193
By using \isacommand{back}, we construct the proof that uses the
109
+ − 194
second assumption. While in the proof above, it does not really matter which
+ − 195
assumption is used, in more interesting cases provability might depend
+ − 196
on exploring different possibilities.
99
+ − 197
93
+ − 198
\begin{readmore}
+ − 199
See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy
109
+ − 200
sequences. In day-to-day Isabelle programming, however, one rarely
+ − 201
constructs sequences explicitly, but uses the predefined tactics and
+ − 202
tactic combinators instead.
93
+ − 203
\end{readmore}
+ − 204
104
+ − 205
It might be surprising that tactics, which transform
109
+ − 206
one goal state to the next, are functions from theorems to theorem
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 207
(sequences). The surprise resolves by knowing that every
104
+ − 208
goal state is indeed a theorem. To shed more light on this,
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 209
let us modify the code of @{ML all_tac} to obtain the following
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 210
tactic
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 211
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 212
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 213
ML{*fun my_print_tac ctxt thm =
132
+ − 214
let
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 215
val _ = writeln (string_of_thm_no_vars ctxt thm)
132
+ − 216
in
+ − 217
Seq.single thm
+ − 218
end*}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 219
109
+ − 220
text_raw {*
+ − 221
\begin{figure}[p]
173
+ − 222
\begin{boxedminipage}{\textwidth}
109
+ − 223
\begin{isabelle}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 224
*}
105
+ − 225
lemma shows "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 226
apply(tactic {* my_print_tac @{context} *})
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 227
109
+ − 228
txt{* \begin{minipage}{\textwidth}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 229
@{subgoals [display]}
109
+ − 230
\end{minipage}\medskip
+ − 231
+ − 232
\begin{minipage}{\textwidth}
+ − 233
\small\colorbox{gray!20}{
+ − 234
\begin{tabular}{@ {}l@ {}}
+ − 235
internal goal state:\\
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 236
@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}
109
+ − 237
\end{tabular}}
+ − 238
\end{minipage}\medskip
93
+ − 239
*}
+ − 240
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 241
apply(rule conjI)
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 242
apply(tactic {* my_print_tac @{context} *})
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 243
109
+ − 244
txt{* \begin{minipage}{\textwidth}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 245
@{subgoals [display]}
109
+ − 246
\end{minipage}\medskip
+ − 247
+ − 248
\begin{minipage}{\textwidth}
+ − 249
\small\colorbox{gray!20}{
+ − 250
\begin{tabular}{@ {}l@ {}}
+ − 251
internal goal state:\\
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 252
@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}
109
+ − 253
\end{tabular}}
+ − 254
\end{minipage}\medskip
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 255
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 256
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 257
apply(assumption)
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 258
apply(tactic {* my_print_tac @{context} *})
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 259
109
+ − 260
txt{* \begin{minipage}{\textwidth}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 261
@{subgoals [display]}
109
+ − 262
\end{minipage}\medskip
+ − 263
+ − 264
\begin{minipage}{\textwidth}
+ − 265
\small\colorbox{gray!20}{
+ − 266
\begin{tabular}{@ {}l@ {}}
+ − 267
internal goal state:\\
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 268
@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}
109
+ − 269
\end{tabular}}
+ − 270
\end{minipage}\medskip
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 271
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 272
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 273
apply(assumption)
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 274
apply(tactic {* my_print_tac @{context} *})
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 275
109
+ − 276
txt{* \begin{minipage}{\textwidth}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 277
@{subgoals [display]}
109
+ − 278
\end{minipage}\medskip
+ − 279
+ − 280
\begin{minipage}{\textwidth}
+ − 281
\small\colorbox{gray!20}{
+ − 282
\begin{tabular}{@ {}l@ {}}
+ − 283
internal goal state:\\
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 284
@{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"}
109
+ − 285
\end{tabular}}
+ − 286
\end{minipage}\medskip
+ − 287
*}
+ − 288
done
+ − 289
text_raw {*
+ − 290
\end{isabelle}
173
+ − 291
\end{boxedminipage}
118
+ − 292
\caption{The figure shows a proof where each intermediate goal state is
+ − 293
printed by the Isabelle system and by @{ML my_print_tac}. The latter shows
+ − 294
the goal state as represented internally (highlighted boxes). This
173
+ − 295
tactic shows that every goal state in Isabelle is represented by a theorem:
156
+ − 296
when you start the proof of \mbox{@{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"}} the theorem is
+ − 297
@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}; when you finish the proof the
118
+ − 298
theorem is @{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"}.\label{fig:goalstates}}
109
+ − 299
\end{figure}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 300
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 301
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 302
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 303
text {*
109
+ − 304
which prints out the given theorem (using the string-function defined in
+ − 305
Section~\ref{sec:printing}) and then behaves like @{ML all_tac}. With this
+ − 306
tactic we are in the position to inspect every goal state in a
+ − 307
proof. Consider now the proof in Figure~\ref{fig:goalstates}: as can be seen,
+ − 308
internally every goal state is an implication of the form
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 309
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 310
@{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 311
109
+ − 312
where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are
+ − 313
the subgoals. So after setting up the lemma, the goal state is always of the
+ − 314
form @{text "C \<Longrightarrow> (C)"}; when the proof is finished we are left with @{text
241
+ − 315
"(C)"}.\footnote{This only applies to single statements. If the lemma
+ − 316
contains more than one statement, then one has more such implications.}
+ − 317
Since the goal @{term C} can potentially be an implication, there is a
+ − 318
``protector'' wrapped around it (the wrapper is the outermost constant
+ − 319
@{text "Const (\"prop\", bool \<Rightarrow> bool)"}; however this constant is invisible
+ − 320
in the figure). This wrapper prevents that premises of @{text C} are
231
+ − 321
misinterpreted as open subgoals. While tactics can operate on the subgoals
109
+ − 322
(the @{text "A\<^isub>i"} above), they are expected to leave the conclusion
+ − 323
@{term C} intact, with the exception of possibly instantiating schematic
+ − 324
variables. If you use the predefined tactics, which we describe in the next
+ − 325
section, this will always be the case.
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 326
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 327
\begin{readmore}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 328
For more information about the internals of goals see \isccite{sec:tactical-goals}.
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 329
\end{readmore}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 330
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 331
*}
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 332
194
+ − 333
section {* Simple Tactics\label{sec:simpletacs} *}
93
+ − 334
99
+ − 335
text {*
256
+ − 336
Let us start with explaining the simple tactic @{ML [index] print_tac}, which is quite useful
173
+ − 337
for low-level debugging of tactics. It just prints out a message and the current
+ − 338
goal state. Unlike @{ML my_print_tac} shown earlier, it prints the goal state
+ − 339
as the user would see it. For example, processing the proof
105
+ − 340
*}
+ − 341
+ − 342
lemma shows "False \<Longrightarrow> True"
+ − 343
apply(tactic {* print_tac "foo message" *})
109
+ − 344
txt{*gives:\medskip
+ − 345
+ − 346
\begin{minipage}{\textwidth}\small
107
+ − 347
@{text "foo message"}\\[3mm]
+ − 348
@{prop "False \<Longrightarrow> True"}\\
+ − 349
@{text " 1. False \<Longrightarrow> True"}\\
+ − 350
\end{minipage}
+ − 351
*}
105
+ − 352
(*<*)oops(*>*)
+ − 353
+ − 354
text {*
213
+ − 355
A simple tactic for easy discharge of any proof obligations is
256
+ − 356
@{ML [index] cheat_tac in SkipProof}. This tactic corresponds to
192
+ − 357
the Isabelle command \isacommand{sorry} and is sometimes useful
+ − 358
during the development of tactics.
+ − 359
*}
+ − 360
213
+ − 361
lemma shows "False" and "Goldbach_conjecture"
192
+ − 362
apply(tactic {* SkipProof.cheat_tac @{theory} *})
+ − 363
txt{*\begin{minipage}{\textwidth}
+ − 364
@{subgoals [display]}
+ − 365
\end{minipage}*}
+ − 366
(*<*)oops(*>*)
+ − 367
+ − 368
text {*
241
+ − 369
This tactic works however only if the quick-and-dirty mode of Isabelle
+ − 370
is switched on.
+ − 371
256
+ − 372
Another simple tactic is the function @{ML [index] atac}, which, as shown in the previous
105
+ − 373
section, corresponds to the assumption command.
99
+ − 374
*}
+ − 375
+ − 376
lemma shows "P \<Longrightarrow> P"
93
+ − 377
apply(tactic {* atac 1 *})
109
+ − 378
txt{*\begin{minipage}{\textwidth}
+ − 379
@{subgoals [display]}
+ − 380
\end{minipage}*}
+ − 381
(*<*)oops(*>*)
93
+ − 382
99
+ − 383
text {*
256
+ − 384
Similarly, @{ML [index] rtac}, @{ML [index] dtac}, @{ML [index] etac} and
+ − 385
@{ML [index] ftac} correspond (roughly)
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 386
to @{text rule}, @{text drule}, @{text erule} and @{text frule},
213
+ − 387
respectively. Each of them take a theorem as argument and attempt to
109
+ − 388
apply it to a goal. Below are three self-explanatory examples.
99
+ − 389
*}
+ − 390
+ − 391
lemma shows "P \<and> Q"
93
+ − 392
apply(tactic {* rtac @{thm conjI} 1 *})
104
+ − 393
txt{*\begin{minipage}{\textwidth}
+ − 394
@{subgoals [display]}
+ − 395
\end{minipage}*}
93
+ − 396
(*<*)oops(*>*)
+ − 397
99
+ − 398
lemma shows "P \<and> Q \<Longrightarrow> False"
93
+ − 399
apply(tactic {* etac @{thm conjE} 1 *})
104
+ − 400
txt{*\begin{minipage}{\textwidth}
+ − 401
@{subgoals [display]}
+ − 402
\end{minipage}*}
93
+ − 403
(*<*)oops(*>*)
+ − 404
+ − 405
lemma shows "False \<and> True \<Longrightarrow> False"
+ − 406
apply(tactic {* dtac @{thm conjunct2} 1 *})
104
+ − 407
txt{*\begin{minipage}{\textwidth}
+ − 408
@{subgoals [display]}
+ − 409
\end{minipage}*}
93
+ − 410
(*<*)oops(*>*)
+ − 411
+ − 412
text {*
256
+ − 413
The function @{ML [index] resolve_tac} is similar to @{ML [index] rtac}, except that it
105
+ − 414
expects a list of theorems as arguments. From this list it will apply the
+ − 415
first applicable theorem (later theorems that are also applicable can be
+ − 416
explored via the lazy sequences mechanism). Given the code
93
+ − 417
*}
+ − 418
238
+ − 419
ML{*val resolve_xmp_tac = resolve_tac [@{thm impI}, @{thm conjI}]*}
99
+ − 420
+ − 421
text {*
+ − 422
an example for @{ML resolve_tac} is the following proof where first an outermost
+ − 423
implication is analysed and then an outermost conjunction.
+ − 424
*}
+ − 425
+ − 426
lemma shows "C \<longrightarrow> (A \<and> B)" and "(A \<longrightarrow> B) \<and> C"
238
+ − 427
apply(tactic {* resolve_xmp_tac 1 *})
+ − 428
apply(tactic {* resolve_xmp_tac 2 *})
104
+ − 429
txt{*\begin{minipage}{\textwidth}
+ − 430
@{subgoals [display]}
+ − 431
\end{minipage}*}
99
+ − 432
(*<*)oops(*>*)
+ − 433
+ − 434
text {*
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 435
Similar versions taking a list of theorems exist for the tactics
256
+ − 436
@{ML dtac} (@{ML [index] dresolve_tac}), @{ML etac}
+ − 437
(@{ML [index] eresolve_tac}) and so on.
109
+ − 438
105
+ − 439
256
+ − 440
Another simple tactic is @{ML [index] cut_facts_tac}. It inserts a list of theorems
109
+ − 441
into the assumptions of the current goal state. For example
107
+ − 442
*}
99
+ − 443
107
+ − 444
lemma shows "True \<noteq> False"
+ − 445
apply(tactic {* cut_facts_tac [@{thm True_def}, @{thm False_def}] 1 *})
109
+ − 446
txt{*produces the goal state\medskip
+ − 447
+ − 448
\begin{minipage}{\textwidth}
107
+ − 449
@{subgoals [display]}
+ − 450
\end{minipage}*}
+ − 451
(*<*)oops(*>*)
+ − 452
+ − 453
text {*
105
+ − 454
Since rules are applied using higher-order unification, an automatic proof
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 455
procedure might become too fragile, if it just applies inference rules as
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 456
shown above. The reason is that a number of rules introduce meta-variables
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 457
into the goal state. Consider for example the proof
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 458
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 459
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 460
lemma shows "\<forall>x\<in>A. P x \<Longrightarrow> Q x"
118
+ − 461
apply(tactic {* dtac @{thm bspec} 1 *})
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 462
txt{*\begin{minipage}{\textwidth}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 463
@{subgoals [display]}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 464
\end{minipage}*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 465
(*<*)oops(*>*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 466
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 467
text {*
149
+ − 468
where the application of rule @{text bspec} generates two subgoals involving the
109
+ − 469
meta-variable @{text "?x"}. Now, if you are not careful, tactics
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 470
applied to the first subgoal might instantiate this meta-variable in such a
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 471
way that the second subgoal becomes unprovable. If it is clear what the @{text "?x"}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 472
should be, then this situation can be avoided by introducing a more
241
+ − 473
constrained version of the @{text bspec}-rule. Such constraints can be given by
109
+ − 474
pre-instantiating theorems with other theorems. One function to do this is
256
+ − 475
@{ML [index] RS}
105
+ − 476
+ − 477
@{ML_response_fake [display,gray]
+ − 478
"@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"}
+ − 479
109
+ − 480
which in the example instantiates the first premise of the @{text conjI}-rule
+ − 481
with the rule @{text disjI1}. If the instantiation is impossible, as in the
+ − 482
case of
107
+ − 483
+ − 484
@{ML_response_fake_both [display,gray]
+ − 485
"@{thm conjI} RS @{thm mp}"
+ − 486
"*** Exception- THM (\"RSN: no unifiers\", 1,
+ − 487
[\"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\", \"\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q\"]) raised"}
+ − 488
256
+ − 489
then the function raises an exception. The function @{ML [index] RSN} is similar to @{ML RS}, but
109
+ − 490
takes an additional number as argument that makes explicit which premise
107
+ − 491
should be instantiated.
+ − 492
213
+ − 493
To improve readability of the theorems we shall produce below, we will use the
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 494
function @{ML no_vars} from Section~\ref{sec:printing}, which transforms
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 495
schematic variables into free ones. Using this function for the first @{ML
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 496
RS}-expression above produces the more readable result:
105
+ − 497
+ − 498
@{ML_response_fake [display,gray]
+ − 499
"no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"}
+ − 500
107
+ − 501
If you want to instantiate more than one premise of a theorem, you can use
256
+ − 502
the function @{ML [index] MRS}:
105
+ − 503
+ − 504
@{ML_response_fake [display,gray]
+ − 505
"no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})"
+ − 506
"\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"}
+ − 507
+ − 508
If you need to instantiate lists of theorems, you can use the
256
+ − 509
functions @{ML RL} and @{ML [index] MRL}. For example in the code below,
109
+ − 510
every theorem in the second list is instantiated with every
+ − 511
theorem in the first.
105
+ − 512
+ − 513
@{ML_response_fake [display,gray]
209
+ − 514
"map (no_vars @{context})
+ − 515
([@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}])"
105
+ − 516
"[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa,
+ − 517
\<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa,
+ − 518
(P \<Longrightarrow> Q) \<Longrightarrow> (P \<longrightarrow> Q) \<or> Qa,
+ − 519
Q \<Longrightarrow> (P \<or> Q) \<or> Qa]"}
+ − 520
+ − 521
\begin{readmore}
+ − 522
The combinators for instantiating theorems are defined in @{ML_file "Pure/drule.ML"}.
+ − 523
\end{readmore}
95
+ − 524
109
+ − 525
Often proofs on the ML-level involve elaborate operations on assumptions and
+ − 526
@{text "\<And>"}-quantified variables. To do such operations using the basic tactics
128
+ − 527
shown so far is very unwieldy and brittle. Some convenience and
256
+ − 528
safety is provided by @{ML [index] SUBPROOF}. This tactic fixes the parameters
109
+ − 529
and binds the various components of a goal state to a record.
105
+ − 530
To see what happens, assume the function defined in Figure~\ref{fig:sptac}, which
109
+ − 531
takes a record and just prints out the content of this record (using the
+ − 532
string transformation functions from in Section~\ref{sec:printing}). Consider
+ − 533
now the proof:
95
+ − 534
*}
+ − 535
99
+ − 536
text_raw{*
173
+ − 537
\begin{figure}[t]
177
+ − 538
\begin{minipage}{\textwidth}
99
+ − 539
\begin{isabelle}
+ − 540
*}
95
+ − 541
ML{*fun sp_tac {prems, params, asms, concl, context, schematics} =
132
+ − 542
let
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 543
val string_of_params = string_of_cterms context params
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 544
val string_of_asms = string_of_cterms context asms
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 545
val string_of_concl = string_of_cterm context concl
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 546
val string_of_prems = string_of_thms_no_vars context prems
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 547
val string_of_schms = string_of_cterms context (snd schematics)
95
+ − 548
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 549
val _ = (writeln ("params: " ^ string_of_params);
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 550
writeln ("schematics: " ^ string_of_schms);
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 551
writeln ("assumptions: " ^ string_of_asms);
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 552
writeln ("conclusion: " ^ string_of_concl);
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 553
writeln ("premises: " ^ string_of_prems))
132
+ − 554
in
+ − 555
no_tac
+ − 556
end*}
99
+ − 557
text_raw{*
+ − 558
\end{isabelle}
177
+ − 559
\end{minipage}
99
+ − 560
\caption{A function that prints out the various parameters provided by the tactic
105
+ − 561
@{ML SUBPROOF}. It uses the functions defined in Section~\ref{sec:printing} for
+ − 562
extracting strings from @{ML_type cterm}s and @{ML_type thm}s.\label{fig:sptac}}
99
+ − 563
\end{figure}
+ − 564
*}
95
+ − 565
+ − 566
99
+ − 567
lemma shows "\<And>x y. A x y \<Longrightarrow> B y x \<longrightarrow> C (?z y) x"
95
+ − 568
apply(tactic {* SUBPROOF sp_tac @{context} 1 *})?
+ − 569
+ − 570
txt {*
109
+ − 571
The tactic produces the following printout:
95
+ − 572
99
+ − 573
\begin{quote}\small
95
+ − 574
\begin{tabular}{ll}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 575
params: & @{term x}, @{term y}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 576
schematics: & @{term z}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 577
assumptions: & @{term "A x y"}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 578
conclusion: & @{term "B y x \<longrightarrow> C (z y) x"}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 579
premises: & @{term "A x y"}
95
+ − 580
\end{tabular}
99
+ − 581
\end{quote}
+ − 582
149
+ − 583
Notice in the actual output the brown colour of the variables @{term x} and
105
+ − 584
@{term y}. Although they are parameters in the original goal, they are fixed inside
109
+ − 585
the subproof. By convention these fixed variables are printed in brown colour.
+ − 586
Similarly the schematic variable @{term z}. The assumption, or premise,
105
+ − 587
@{prop "A x y"} is bound as @{ML_type cterm} to the record-variable
109
+ − 588
@{text asms}, but also as @{ML_type thm} to @{text prems}.
95
+ − 589
109
+ − 590
Notice also that we had to append @{text [quotes] "?"} to the
256
+ − 591
\isacommand{apply}-command. The reason is that @{ML [index] SUBPROOF} normally
109
+ − 592
expects that the subgoal is solved completely. Since in the function @{ML
+ − 593
sp_tac} we returned the tactic @{ML no_tac}, the subproof obviously
+ − 594
fails. The question-mark allows us to recover from this failure in a
239
+ − 595
graceful manner so that the output messages are not overwritten by an
109
+ − 596
``empty sequence'' error message.
99
+ − 597
+ − 598
If we continue the proof script by applying the @{text impI}-rule
95
+ − 599
*}
+ − 600
+ − 601
apply(rule impI)
+ − 602
apply(tactic {* SUBPROOF sp_tac @{context} 1 *})?
+ − 603
+ − 604
txt {*
118
+ − 605
then the tactic prints out:
95
+ − 606
99
+ − 607
\begin{quote}\small
95
+ − 608
\begin{tabular}{ll}
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 609
params: & @{term x}, @{term y}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 610
schematics: & @{term z}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 611
assumptions: & @{term "A x y"}, @{term "B y x"}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 612
conclusion: & @{term "C (z y) x"}\\
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 613
premises: & @{term "A x y"}, @{term "B y x"}
95
+ − 614
\end{tabular}
99
+ − 615
\end{quote}
95
+ − 616
*}
+ − 617
(*<*)oops(*>*)
+ − 618
99
+ − 619
text {*
109
+ − 620
Now also @{term "B y x"} is an assumption bound to @{text asms} and @{text prems}.
99
+ − 621
105
+ − 622
One convenience of @{ML SUBPROOF} is that we can apply the assumptions
99
+ − 623
using the usual tactics, because the parameter @{text prems}
109
+ − 624
contains them as theorems. With this you can easily
+ − 625
implement a tactic that behaves almost like @{ML atac}:
99
+ − 626
*}
+ − 627
104
+ − 628
ML{*val atac' = SUBPROOF (fn {prems, ...} => resolve_tac prems 1)*}
107
+ − 629
+ − 630
text {*
109
+ − 631
If you apply @{ML atac'} to the next lemma
107
+ − 632
*}
+ − 633
109
+ − 634
lemma shows "\<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y"
104
+ − 635
apply(tactic {* atac' @{context} 1 *})
109
+ − 636
txt{* it will produce
99
+ − 637
@{subgoals [display]} *}
+ − 638
(*<*)oops(*>*)
+ − 639
104
+ − 640
text {*
241
+ − 641
The restriction in this tactic which is not present in @{ML atac} is that it
+ − 642
cannot instantiate any schematic variables. This might be seen as a defect,
+ − 643
but it is actually an advantage in the situations for which @{ML SUBPROOF}
+ − 644
was designed: the reason is that, as mentioned before, instantiation of
+ − 645
schematic variables can affect several goals and can render them
+ − 646
unprovable. @{ML SUBPROOF} is meant to avoid this.
104
+ − 647
241
+ − 648
Notice that @{ML atac'} inside @{ML SUBPROOF} calls @{ML resolve_tac} with
+ − 649
the subgoal number @{text "1"} and also the outer call to @{ML SUBPROOF} in
+ − 650
the \isacommand{apply}-step uses @{text "1"}. This is another advantage of
+ − 651
@{ML SUBPROOF}: the addressing inside it is completely local to the tactic
+ − 652
inside the subproof. It is therefore possible to also apply @{ML atac'} to
+ − 653
the second goal by just writing:
104
+ − 654
*}
+ − 655
109
+ − 656
lemma shows "True" and "\<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y"
104
+ − 657
apply(tactic {* atac' @{context} 2 *})
105
+ − 658
apply(rule TrueI)
+ − 659
done
104
+ − 660
95
+ − 661
93
+ − 662
text {*
105
+ − 663
\begin{readmore}
+ − 664
The function @{ML SUBPROOF} is defined in @{ML_file "Pure/subgoal.ML"} and
+ − 665
also described in \isccite{sec:results}.
+ − 666
\end{readmore}
+ − 667
256
+ − 668
Similar but less powerful functions than @{ML SUBPROOF} are @{ML [index] SUBGOAL}
+ − 669
and @{ML [index] CSUBGOAL}. They allow you to inspect a given subgoal (the former
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 670
presents the subgoal as a @{ML_type term}, while the latter as a @{ML_type
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 671
cterm}). With this you can implement a tactic that applies a rule according
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 672
to the topmost logic connective in the subgoal (to illustrate this we only
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 673
analyse a few connectives). The code of the tactic is as
238
+ − 674
follows.
93
+ − 675
*}
+ − 676
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 677
ML %linenosgray{*fun select_tac (t, i) =
99
+ − 678
case t of
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 679
@{term "Trueprop"} $ t' => select_tac (t', i)
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 680
| @{term "op \<Longrightarrow>"} $ _ $ t' => select_tac (t', i)
99
+ − 681
| @{term "op \<and>"} $ _ $ _ => rtac @{thm conjI} i
+ − 682
| @{term "op \<longrightarrow>"} $ _ $ _ => rtac @{thm impI} i
+ − 683
| @{term "Not"} $ _ => rtac @{thm notI} i
+ − 684
| Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i
238
+ − 685
| _ => all_tac*}text_raw{*\label{tac:selecttac}*}
99
+ − 686
105
+ − 687
text {*
109
+ − 688
The input of the function is a term representing the subgoal and a number
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 689
specifying the subgoal of interest. In Line 3 you need to descend under the
109
+ − 690
outermost @{term "Trueprop"} in order to get to the connective you like to
+ − 691
analyse. Otherwise goals like @{prop "A \<and> B"} are not properly
+ − 692
analysed. Similarly with meta-implications in the next line. While for the
+ − 693
first five patterns we can use the @{text "@term"}-antiquotation to
+ − 694
construct the patterns, the pattern in Line 8 cannot be constructed in this
+ − 695
way. The reason is that an antiquotation would fix the type of the
+ − 696
quantified variable. So you really have to construct the pattern using the
156
+ − 697
basic term-constructors. This is not necessary in other cases, because their
+ − 698
type is always fixed to function types involving only the type @{typ
255
ef1da1abee46
added infrastructure for index; antiquotations have now the options [index] and [indexc]
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 699
bool}. (See Section \ref{sec:terms_manually} about constructing terms
156
+ − 700
manually.) For the catch-all pattern, we chose to just return @{ML all_tac}.
+ − 701
Consequently, @{ML select_tac} never fails.
+ − 702
105
+ − 703
107
+ − 704
Let us now see how to apply this tactic. Consider the four goals:
105
+ − 705
*}
+ − 706
+ − 707
+ − 708
lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F"
104
+ − 709
apply(tactic {* SUBGOAL select_tac 4 *})
+ − 710
apply(tactic {* SUBGOAL select_tac 3 *})
+ − 711
apply(tactic {* SUBGOAL select_tac 2 *})
99
+ − 712
apply(tactic {* SUBGOAL select_tac 1 *})
107
+ − 713
txt{* \begin{minipage}{\textwidth}
+ − 714
@{subgoals [display]}
+ − 715
\end{minipage} *}
99
+ − 716
(*<*)oops(*>*)
+ − 717
+ − 718
text {*
107
+ − 719
where in all but the last the tactic applied an introduction rule.
109
+ − 720
Note that we applied the tactic to the goals in ``reverse'' order.
+ − 721
This is a trick in order to be independent from the subgoals that are
+ − 722
produced by the rule. If we had applied it in the other order
105
+ − 723
*}
+ − 724
+ − 725
lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F"
+ − 726
apply(tactic {* SUBGOAL select_tac 1 *})
+ − 727
apply(tactic {* SUBGOAL select_tac 3 *})
+ − 728
apply(tactic {* SUBGOAL select_tac 4 *})
+ − 729
apply(tactic {* SUBGOAL select_tac 5 *})
+ − 730
(*<*)oops(*>*)
99
+ − 731
105
+ − 732
text {*
109
+ − 733
then we have to be careful to not apply the tactic to the two subgoals produced by
+ − 734
the first goal. To do this can result in quite messy code. In contrast,
107
+ − 735
the ``reverse application'' is easy to implement.
104
+ − 736
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 737
Of course, this example is
149
+ − 738
contrived: there are much simpler methods available in Isabelle for
243
+ − 739
implementing a tactic analysing a goal according to its topmost
149
+ − 740
connective. These simpler methods use tactic combinators, which we will
+ − 741
explain in the next section.
147
+ − 742
105
+ − 743
*}
+ − 744
+ − 745
section {* Tactic Combinators *}
+ − 746
+ − 747
text {*
109
+ − 748
The purpose of tactic combinators is to build compound tactics out of
+ − 749
smaller tactics. In the previous section we already used @{ML THEN}, which
+ − 750
just strings together two tactics in a sequence. For example:
93
+ − 751
*}
+ − 752
105
+ − 753
lemma shows "(Foo \<and> Bar) \<and> False"
+ − 754
apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *})
+ − 755
txt {* \begin{minipage}{\textwidth}
+ − 756
@{subgoals [display]}
+ − 757
\end{minipage} *}
+ − 758
(*<*)oops(*>*)
99
+ − 759
105
+ − 760
text {*
213
+ − 761
If you want to avoid the hard-coded subgoal addressing, then, as
+ − 762
seen earlier, you can use
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 763
the ``primed'' version of @{ML THEN}. For example:
105
+ − 764
*}
93
+ − 765
99
+ − 766
lemma shows "(Foo \<and> Bar) \<and> False"
105
+ − 767
apply(tactic {* (rtac @{thm conjI} THEN' rtac @{thm conjI}) 1 *})
+ − 768
txt {* \begin{minipage}{\textwidth}
+ − 769
@{subgoals [display]}
+ − 770
\end{minipage} *}
93
+ − 771
(*<*)oops(*>*)
+ − 772
105
+ − 773
text {*
213
+ − 774
Here you have to specify the subgoal of interest only once and
109
+ − 775
it is consistently applied to the component tactics.
107
+ − 776
For most tactic combinators such a ``primed'' version exists and
+ − 777
in what follows we will usually prefer it over the ``unprimed'' one.
+ − 778
+ − 779
If there is a list of tactics that should all be tried out in
256
+ − 780
sequence, you can use the combinator @{ML [index] EVERY'}. For example
109
+ − 781
the function @{ML foo_tac'} from page~\pageref{tac:footacprime} can also
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 782
be written as:
107
+ − 783
*}
+ − 784
+ − 785
ML{*val foo_tac'' = EVERY' [etac @{thm disjE}, rtac @{thm disjI2},
+ − 786
atac, rtac @{thm disjI1}, atac]*}
105
+ − 787
107
+ − 788
text {*
109
+ − 789
There is even another way of implementing this tactic: in automatic proof
+ − 790
procedures (in contrast to tactics that might be called by the user) there
+ − 791
are often long lists of tactics that are applied to the first
+ − 792
subgoal. Instead of writing the code above and then calling @{ML "foo_tac'' 1"},
+ − 793
you can also just write
107
+ − 794
*}
+ − 795
+ − 796
ML{*val foo_tac1 = EVERY1 [etac @{thm disjE}, rtac @{thm disjI2},
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 797
atac, rtac @{thm disjI1}, atac]*}
107
+ − 798
+ − 799
text {*
118
+ − 800
and call @{ML foo_tac1}.
109
+ − 801
256
+ − 802
With the combinators @{ML THEN'}, @{ML EVERY'} and @{ML [index] EVERY1} it must be
109
+ − 803
guaranteed that all component tactics successfully apply; otherwise the
+ − 804
whole tactic will fail. If you rather want to try out a number of tactics,
256
+ − 805
then you can use the combinator @{ML [index] ORELSE'} for two tactics, and @{ML
+ − 806
[index] FIRST'} (or @{ML [index] FIRST1}) for a list of tactics. For example, the tactic
109
+ − 807
105
+ − 808
*}
+ − 809
238
+ − 810
ML{*val orelse_xmp_tac = rtac @{thm disjI1} ORELSE' rtac @{thm conjI}*}
99
+ − 811
105
+ − 812
text {*
243
+ − 813
will first try out whether rule @{text disjI} applies and in case of failure
+ − 814
will try @{text conjI}. To see this consider the proof
105
+ − 815
*}
+ − 816
99
+ − 817
lemma shows "True \<and> False" and "Foo \<or> Bar"
238
+ − 818
apply(tactic {* orelse_xmp_tac 2 *})
+ − 819
apply(tactic {* orelse_xmp_tac 1 *})
107
+ − 820
txt {* which results in the goal state
+ − 821
+ − 822
\begin{minipage}{\textwidth}
+ − 823
@{subgoals [display]}
+ − 824
\end{minipage}
+ − 825
*}
93
+ − 826
(*<*)oops(*>*)
+ − 827
+ − 828
+ − 829
text {*
109
+ − 830
Using @{ML FIRST'} we can simplify our @{ML select_tac} from Page~\pageref{tac:selecttac}
+ − 831
as follows:
107
+ − 832
*}
+ − 833
+ − 834
ML{*val select_tac' = FIRST' [rtac @{thm conjI}, rtac @{thm impI},
238
+ − 835
rtac @{thm notI}, rtac @{thm allI}, K all_tac]*}text_raw{*\label{tac:selectprime}*}
107
+ − 836
+ − 837
text {*
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 838
Since we like to mimic the behaviour of @{ML select_tac} as closely as possible,
109
+ − 839
we must include @{ML all_tac} at the end of the list, otherwise the tactic will
118
+ − 840
fail if no rule applies (we also have to wrap @{ML all_tac} using the
109
+ − 841
@{ML K}-combinator, because it does not take a subgoal number as argument). You can
+ − 842
test the tactic on the same goals:
107
+ − 843
*}
+ − 844
+ − 845
lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F"
+ − 846
apply(tactic {* select_tac' 4 *})
+ − 847
apply(tactic {* select_tac' 3 *})
+ − 848
apply(tactic {* select_tac' 2 *})
+ − 849
apply(tactic {* select_tac' 1 *})
+ − 850
txt{* \begin{minipage}{\textwidth}
+ − 851
@{subgoals [display]}
+ − 852
\end{minipage} *}
+ − 853
(*<*)oops(*>*)
+ − 854
+ − 855
text {*
109
+ − 856
Since such repeated applications of a tactic to the reverse order of
+ − 857
\emph{all} subgoals is quite common, there is the tactic combinator
256
+ − 858
@{ML [index] ALLGOALS} that simplifies this. Using this combinator you can simply
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 859
write: *}
107
+ − 860
+ − 861
lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F"
+ − 862
apply(tactic {* ALLGOALS select_tac' *})
+ − 863
txt{* \begin{minipage}{\textwidth}
+ − 864
@{subgoals [display]}
+ − 865
\end{minipage} *}
+ − 866
(*<*)oops(*>*)
+ − 867
+ − 868
text {*
109
+ − 869
Remember that we chose to implement @{ML select_tac'} so that it
243
+ − 870
always succeeds by adding @{ML all_tac} at the end of the tactic
256
+ − 871
list. The same can be achieved with the tactic combinator @{ML [index] TRY}.
243
+ − 872
For example:
+ − 873
*}
+ − 874
+ − 875
ML{*val select_tac'' = TRY o FIRST' [rtac @{thm conjI}, rtac @{thm impI},
+ − 876
rtac @{thm notI}, rtac @{thm allI}]*}
+ − 877
text_raw{*\label{tac:selectprimeprime}*}
+ − 878
+ − 879
text {*
+ − 880
This tactic behaves in the same way as @{ML select_tac'}: it tries out
+ − 881
one of the given tactics and if none applies leaves the goal state
+ − 882
unchanged. This, however, can be potentially very confusing when visible to
+ − 883
the user, for example, in cases where the goal is the form
+ − 884
107
+ − 885
*}
+ − 886
+ − 887
lemma shows "E \<Longrightarrow> F"
+ − 888
apply(tactic {* select_tac' 1 *})
+ − 889
txt{* \begin{minipage}{\textwidth}
+ − 890
@{subgoals [display]}
+ − 891
\end{minipage} *}
+ − 892
(*<*)oops(*>*)
+ − 893
+ − 894
text {*
243
+ − 895
In this case no rule applies, but because of @{ML TRY} or the inclusion of @{ML all_tac}
+ − 896
the tactics do not fail. The problem with this is that for the user there is little
109
+ − 897
chance to see whether or not progress in the proof has been made. By convention
+ − 898
therefore, tactics visible to the user should either change something or fail.
+ − 899
+ − 900
To comply with this convention, we could simply delete the @{ML "K all_tac"}
+ − 901
from the end of the theorem list. As a result @{ML select_tac'} would only
+ − 902
succeed on goals where it can make progress. But for the sake of argument,
+ − 903
let us suppose that this deletion is \emph{not} an option. In such cases, you can
256
+ − 904
use the combinator @{ML [index] CHANGED} to make sure the subgoal has been changed
109
+ − 905
by the tactic. Because now
+ − 906
107
+ − 907
*}
+ − 908
+ − 909
lemma shows "E \<Longrightarrow> F"
+ − 910
apply(tactic {* CHANGED (select_tac' 1) *})(*<*)?(*>*)
109
+ − 911
txt{* gives the error message:
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 912
\begin{isabelle}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 913
@{text "*** empty result sequence -- proof command failed"}\\
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 914
@{text "*** At command \"apply\"."}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 915
\end{isabelle}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 916
*}(*<*)oops(*>*)
105
+ − 917
+ − 918
107
+ − 919
text {*
109
+ − 920
We can further extend @{ML select_tac'} so that it not just applies to the topmost
+ − 921
connective, but also to the ones immediately ``underneath'', i.e.~analyse the goal
256
+ − 922
completely. For this you can use the tactic combinator @{ML [index] REPEAT}. As an example
109
+ − 923
suppose the following tactic
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 924
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 925
238
+ − 926
ML{*val repeat_xmp_tac = REPEAT (CHANGED (select_tac' 1)) *}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 927
109
+ − 928
text {* which applied to the proof *}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 929
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 930
lemma shows "((\<not>A) \<and> (\<forall>x. B x)) \<and> (C \<longrightarrow> D)"
238
+ − 931
apply(tactic {* repeat_xmp_tac *})
109
+ − 932
txt{* produces
+ − 933
+ − 934
\begin{minipage}{\textwidth}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 935
@{subgoals [display]}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 936
\end{minipage} *}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 937
(*<*)oops(*>*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 938
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 939
text {*
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 940
Here it is crucial that @{ML select_tac'} is prefixed with @{ML CHANGED},
109
+ − 941
because otherwise @{ML REPEAT} runs into an infinite loop (it applies the
+ − 942
tactic as long as it succeeds). The function
256
+ − 943
@{ML [index] REPEAT1} is similar, but runs the tactic at least once (failing if
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 944
this is not possible).
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 945
238
+ − 946
If you are after the ``primed'' version of @{ML repeat_xmp_tac}, then you
243
+ − 947
can implement it as
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 948
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 949
238
+ − 950
ML{*val repeat_xmp_tac' = REPEAT o CHANGED o select_tac'*}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 951
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 952
text {*
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 953
since there are no ``primed'' versions of @{ML REPEAT} and @{ML CHANGED}.
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 954
243
+ − 955
If you look closely at the goal state above, then you see the tactics @{ML repeat_xmp_tac}
238
+ − 956
and @{ML repeat_xmp_tac'} are not yet quite what we are after: the problem is
109
+ − 957
that goals 2 and 3 are not analysed. This is because the tactic
+ − 958
is applied repeatedly only to the first subgoal. To analyse also all
256
+ − 959
resulting subgoals, you can use the tactic combinator @{ML [index] REPEAT_ALL_NEW}.
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 960
Suppose the tactic
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 961
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 962
238
+ − 963
ML{*val repeat_all_new_xmp_tac = REPEAT_ALL_NEW (CHANGED o select_tac')*}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 964
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 965
text {*
109
+ − 966
you see that the following goal
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 967
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 968
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 969
lemma shows "((\<not>A) \<and> (\<forall>x. B x)) \<and> (C \<longrightarrow> D)"
238
+ − 970
apply(tactic {* repeat_all_new_xmp_tac 1 *})
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 971
txt{* \begin{minipage}{\textwidth}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 972
@{subgoals [display]}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 973
\end{minipage} *}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 974
(*<*)oops(*>*)
93
+ − 975
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 976
text {*
109
+ − 977
is completely analysed according to the theorems we chose to
120
+ − 978
include in @{ML select_tac'}.
109
+ − 979
+ − 980
Recall that tactics produce a lazy sequence of successor goal states. These
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 981
states can be explored using the command \isacommand{back}. For example
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 982
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 983
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 984
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 985
lemma "\<lbrakk>P1 \<or> Q1; P2 \<or> Q2\<rbrakk> \<Longrightarrow> R"
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 986
apply(tactic {* etac @{thm disjE} 1 *})
109
+ − 987
txt{* applies the rule to the first assumption yielding the goal state:\smallskip
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 988
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 989
\begin{minipage}{\textwidth}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 990
@{subgoals [display]}
109
+ − 991
\end{minipage}\smallskip
+ − 992
+ − 993
After typing
+ − 994
*}
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 995
(*<*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 996
oops
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 997
lemma "\<lbrakk>P1 \<or> Q1; P2 \<or> Q2\<rbrakk> \<Longrightarrow> R"
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 998
apply(tactic {* etac @{thm disjE} 1 *})
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 999
(*>*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1000
back
109
+ − 1001
txt{* the rule now applies to the second assumption.\smallskip
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1002
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1003
\begin{minipage}{\textwidth}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1004
@{subgoals [display]}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1005
\end{minipage} *}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1006
(*<*)oops(*>*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1007
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1008
text {*
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1009
Sometimes this leads to confusing behaviour of tactics and also has
109
+ − 1010
the potential to explode the search space for tactics.
+ − 1011
These problems can be avoided by prefixing the tactic with the tactic
256
+ − 1012
combinator @{ML [index] DETERM}.
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1013
*}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1014
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1015
lemma "\<lbrakk>P1 \<or> Q1; P2 \<or> Q2\<rbrakk> \<Longrightarrow> R"
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1016
apply(tactic {* DETERM (etac @{thm disjE} 1) *})
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1017
txt {*\begin{minipage}{\textwidth}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1018
@{subgoals [display]}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1019
\end{minipage} *}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1020
(*<*)oops(*>*)
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1021
text {*
118
+ − 1022
This combinator will prune the search space to just the first successful application.
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1023
Attempting to apply \isacommand{back} in this goal states gives the
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1024
error message:
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1025
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1026
\begin{isabelle}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1027
@{text "*** back: no alternatives"}\\
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1028
@{text "*** At command \"back\"."}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1029
\end{isabelle}
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1030
238
+ − 1031
Recall that we implemented @{ML select_tac'} on Page~\pageref{tac:selectprime} specifically
+ − 1032
so that it always succeeds. We achieved this by adding at the end the tactic @{ML all_tac}.
+ − 1033
We can achieve this also by using the combinator @{ML TRY}. Suppose, for example the
+ − 1034
tactic
+ − 1035
*}
+ − 1036
+ − 1037
ML{*val select_tac'' = FIRST' [rtac @{thm conjI}, rtac @{thm impI},
+ − 1038
rtac @{thm notI}, rtac @{thm allI}]*}
+ − 1039
+ − 1040
text {*
+ − 1041
which will fail if none of the rules applies. However, if you prefix it as follows
+ − 1042
*}
+ − 1043
+ − 1044
ML{*val select_tac''' = TRY o select_tac''*}
+ − 1045
+ − 1046
text {*
+ − 1047
then the tactic @{ML select_tac''} will be tried out and any failure is harnessed.
+ − 1048
We again have to use the construction with \mbox{@{text "TRY o ..."}} since there is
256
+ − 1049
no primed version of @{ML [index] TRY}. The tactic combinator @{ML [index] TRYALL} will try out
238
+ − 1050
a tactic on all subgoals. For example the tactic
+ − 1051
*}
+ − 1052
+ − 1053
ML{*val triv_tac = TRYALL (rtac @{thm TrueI} ORELSE' etac @{thm FalseE})*}
+ − 1054
+ − 1055
text {*
+ − 1056
will solve all trivial subgoals involving @{term True} or @{term "False"}.
+ − 1057
256
+ − 1058
(FIXME: say something about @{ML [index] COND} and COND')
238
+ − 1059
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1060
\begin{readmore}
109
+ − 1061
Most tactic combinators described in this section are defined in @{ML_file "Pure/tctical.ML"}.
238
+ − 1062
Some combinators for the purpose of proof search are implemented in @{ML_file "Pure/search.ML"}.
108
8bea3f74889d
added to the tactical chapter; polished; added the tabularstar environment (which is just tabular*)
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1063
\end{readmore}
107
+ − 1064
105
+ − 1065
*}
+ − 1066
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1067
section {* Simplifier Tactics *}
105
+ − 1068
+ − 1069
text {*
152
+ − 1070
A lot of convenience in the reasoning with Isabelle derives from its
232
+ − 1071
powerful simplifier. The power of the simplifier is a strength and a weakness at
+ − 1072
the same time, because you can easily make the simplifier run into a loop and
+ − 1073
in general its
162
+ − 1074
behaviour can be difficult to predict. There is also a multitude
231
+ − 1075
of options that you can configure to control the behaviour of the simplifier.
162
+ − 1076
We describe some of them in this and the next section.
157
+ − 1077
+ − 1078
There are the following five main tactics behind
162
+ − 1079
the simplifier (in parentheses is their user-level counterpart):
152
+ − 1080
+ − 1081
\begin{isabelle}
157
+ − 1082
\begin{center}
152
+ − 1083
\begin{tabular}{l@ {\hspace{2cm}}l}
256
+ − 1084
@{ML [index] simp_tac} & @{text "(simp (no_asm))"} \\
+ − 1085
@{ML [index] asm_simp_tac} & @{text "(simp (no_asm_simp))"} \\
+ − 1086
@{ML [index] full_simp_tac} & @{text "(simp (no_asm_use))"} \\
+ − 1087
@{ML [index] asm_lr_simp_tac} & @{text "(simp (asm_lr))"} \\
+ − 1088
@{ML [index] asm_full_simp_tac} & @{text "(simp)"}
152
+ − 1089
\end{tabular}
157
+ − 1090
\end{center}
152
+ − 1091
\end{isabelle}
+ − 1092
231
+ − 1093
All of the tactics take a simpset and an integer as argument (the latter as usual
162
+ − 1094
to specify the goal to be analysed). So the proof
152
+ − 1095
*}
+ − 1096
+ − 1097
lemma "Suc (1 + 2) < 3 + 2"
+ − 1098
apply(simp)
+ − 1099
done
+ − 1100
+ − 1101
text {*
157
+ − 1102
corresponds on the ML-level to the tactic
152
+ − 1103
*}
+ − 1104
+ − 1105
lemma "Suc (1 + 2) < 3 + 2"
+ − 1106
apply(tactic {* asm_full_simp_tac @{simpset} 1 *})
+ − 1107
done
+ − 1108
+ − 1109
text {*
162
+ − 1110
If the simplifier cannot make any progress, then it leaves the goal unchanged,
209
+ − 1111
i.e., does not raise any error message. That means if you use it to unfold a
162
+ − 1112
definition for a constant and this constant is not present in the goal state,
+ − 1113
you can still safely apply the simplifier.
152
+ − 1114
162
+ − 1115
When using the simplifier, the crucial information you have to provide is
+ − 1116
the simpset. If this information is not handled with care, then the
+ − 1117
simplifier can easily run into a loop. Therefore a good rule of thumb is to
+ − 1118
use simpsets that are as minimal as possible. It might be surprising that a
+ − 1119
simpset is more complex than just a simple collection of theorems used as
+ − 1120
simplification rules. One reason for the complexity is that the simplifier
+ − 1121
must be able to rewrite inside terms and should also be able to rewrite
231
+ − 1122
according to rules that have preconditions.
157
+ − 1123
+ − 1124
+ − 1125
The rewriting inside terms requires congruence rules, which
+ − 1126
are meta-equalities typical of the form
152
+ − 1127
+ − 1128
\begin{isabelle}
157
+ − 1129
\begin{center}
162
+ − 1130
\mbox{\inferrule{@{text "t\<^isub>1 \<equiv> s\<^isub>1 \<dots> t\<^isub>n \<equiv> s\<^isub>n"}}
157
+ − 1131
{@{text "constr t\<^isub>1\<dots>t\<^isub>n \<equiv> constr s\<^isub>1\<dots>s\<^isub>n"}}}
+ − 1132
\end{center}
152
+ − 1133
\end{isabelle}
+ − 1134
243
+ − 1135
with @{text "constr"} being a constant, like @{const "If"} or @{const "Let"}.
162
+ − 1136
Every simpset contains only
231
+ − 1137
one congruence rule for each term-constructor, which however can be
157
+ − 1138
overwritten. The user can declare lemmas to be congruence rules using the
+ − 1139
attribute @{text "[cong]"}. In HOL, the user usually states these lemmas as
+ − 1140
equations, which are then internally transformed into meta-equations.
+ − 1141
+ − 1142
+ − 1143
The rewriting with rules involving preconditions requires what is in
+ − 1144
Isabelle called a subgoaler, a solver and a looper. These can be arbitrary
232
+ − 1145
tactics that can be installed in a simpset and which are called at
162
+ − 1146
various stages during simplification. However, simpsets also include
157
+ − 1147
simprocs, which can produce rewrite rules on demand (see next
+ − 1148
section). Another component are split-rules, which can simplify for example
+ − 1149
the ``then'' and ``else'' branches of if-statements under the corresponding
231
+ − 1150
preconditions.
157
+ − 1151
162
+ − 1152
157
+ − 1153
\begin{readmore}
+ − 1154
For more information about the simplifier see @{ML_file "Pure/meta_simplifier.ML"}
+ − 1155
and @{ML_file "Pure/simplifier.ML"}. The simplifier for HOL is set up in
243
+ − 1156
@{ML_file "HOL/Tools/simpdata.ML"}. The generic splitter is implemented in
157
+ − 1157
@{ML_file "Provers/splitter.ML"}.
+ − 1158
\end{readmore}
152
+ − 1159
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1160
\begin{readmore}
209
+ − 1161
FIXME: Find the right place: Discrimination nets are implemented
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1162
in @{ML_file "Pure/net.ML"}.
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1163
\end{readmore}
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1164
209
+ − 1165
The most common combinators to modify simpsets are:
152
+ − 1166
+ − 1167
\begin{isabelle}
+ − 1168
\begin{tabular}{ll}
256
+ − 1169
@{ML [index] addsimps} & @{ML [index] delsimps}\\
+ − 1170
@{ML [index] addcongs} & @{ML [index] delcongs}\\
+ − 1171
@{ML [index] addsimprocs} & @{ML [index] delsimprocs}\\
152
+ − 1172
\end{tabular}
+ − 1173
\end{isabelle}
+ − 1174
157
+ − 1175
(FIXME: What about splitters? @{ML addsplits}, @{ML delsplits})
+ − 1176
*}
+ − 1177
+ − 1178
text_raw {*
173
+ − 1179
\begin{figure}[t]
177
+ − 1180
\begin{minipage}{\textwidth}
157
+ − 1181
\begin{isabelle}*}
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1182
ML{*fun print_ss ctxt ss =
157
+ − 1183
let
243
+ − 1184
val {simps, congs, procs, ...} = Simplifier.dest_ss ss
157
+ − 1185
+ − 1186
fun name_thm (nm, thm) =
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1187
" " ^ nm ^ ": " ^ (string_of_thm_no_vars ctxt thm)
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1188
fun name_ctrm (nm, ctrm) =
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1189
" " ^ nm ^ ": " ^ (string_of_cterms ctxt ctrm)
157
+ − 1190
243
+ − 1191
val s = ["Simplification rules:"] @ map name_thm simps @
+ − 1192
["Congruences rules:"] @ map name_thm congs @
+ − 1193
["Simproc patterns:"] @ map name_ctrm procs
157
+ − 1194
in
243
+ − 1195
s |> cat_lines
239
+ − 1196
|> writeln
157
+ − 1197
end*}
+ − 1198
text_raw {*
+ − 1199
\end{isabelle}
177
+ − 1200
\end{minipage}
256
+ − 1201
\caption{The function @{ML [index] dest_ss in Simplifier} returns a record containing
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1202
all printable information stored in a simpset. We are here only interested in the
231
+ − 1203
simplification rules, congruence rules and simprocs.\label{fig:printss}}
157
+ − 1204
\end{figure} *}
+ − 1205
+ − 1206
text {*
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1207
To see how they work, consider the function in Figure~\ref{fig:printss}, which
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1208
prints out some parts of a simpset. If you use it to print out the components of the
256
+ − 1209
empty simpset, i.e., @{ML [index] empty_ss}
157
+ − 1210
+ − 1211
@{ML_response_fake [display,gray]
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1212
"print_ss @{context} empty_ss"
157
+ − 1213
"Simplification rules:
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1214
Congruences rules:
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1215
Simproc patterns:"}
157
+ − 1216
+ − 1217
you can see it contains nothing. This simpset is usually not useful, except as a
+ − 1218
building block to build bigger simpsets. For example you can add to @{ML empty_ss}
+ − 1219
the simplification rule @{thm [source] Diff_Int} as follows:
152
+ − 1220
*}
+ − 1221
157
+ − 1222
ML{*val ss1 = empty_ss addsimps [@{thm Diff_Int} RS @{thm eq_reflection}] *}
+ − 1223
+ − 1224
text {*
162
+ − 1225
Printing then out the components of the simpset gives:
153
+ − 1226
157
+ − 1227
@{ML_response_fake [display,gray]
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1228
"print_ss @{context} ss1"
157
+ − 1229
"Simplification rules:
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1230
??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1231
Congruences rules:
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1232
Simproc patterns:"}
157
+ − 1233
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1234
(FIXME: Why does it print out ??.unknown)
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1235
162
+ − 1236
Adding also the congruence rule @{thm [source] UN_cong}
153
+ − 1237
*}
+ − 1238
157
+ − 1239
ML{*val ss2 = ss1 addcongs [@{thm UN_cong} RS @{thm eq_reflection}] *}
+ − 1240
+ − 1241
text {*
+ − 1242
gives
+ − 1243
+ − 1244
@{ML_response_fake [display,gray]
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1245
"print_ss @{context} ss2"
157
+ − 1246
"Simplification rules:
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1247
??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
157
+ − 1248
Congruences rules:
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1249
UNION: \<lbrakk>A = B; \<And>x. x \<in> B \<Longrightarrow> C x = D x\<rbrakk> \<Longrightarrow> \<Union>x\<in>A. C x \<equiv> \<Union>x\<in>B. D x
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1250
Simproc patterns:"}
157
+ − 1251
+ − 1252
Notice that we had to add these lemmas as meta-equations. The @{ML empty_ss}
+ − 1253
expects this form of the simplification and congruence rules. However, even
162
+ − 1254
when adding these lemmas to @{ML empty_ss} we do not end up with anything useful yet.
157
+ − 1255
256
+ − 1256
In the context of HOL, the first really useful simpset is @{ML [index] HOL_basic_ss}. While
157
+ − 1257
printing out the components of this simpset
+ − 1258
+ − 1259
@{ML_response_fake [display,gray]
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1260
"print_ss @{context} HOL_basic_ss"
157
+ − 1261
"Simplification rules:
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1262
Congruences rules:
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1263
Simproc patterns:"}
157
+ − 1264
+ − 1265
also produces ``nothing'', the printout is misleading. In fact
162
+ − 1266
the @{ML HOL_basic_ss} is setup so that it can solve goals of the
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1267
form
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1268
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1269
\begin{isabelle}
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1270
@{thm TrueI}, @{thm refl[no_vars]}, @{term "t \<equiv> t"} and @{thm FalseE[no_vars]};
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1271
\end{isabelle}
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1272
162
+ − 1273
and also resolve with assumptions. For example:
157
+ − 1274
*}
+ − 1275
+ − 1276
lemma
+ − 1277
"True" and "t = t" and "t \<equiv> t" and "False \<Longrightarrow> Foo" and "\<lbrakk>A; B; C\<rbrakk> \<Longrightarrow> A"
+ − 1278
apply(tactic {* ALLGOALS (simp_tac HOL_basic_ss) *})
+ − 1279
done
+ − 1280
+ − 1281
text {*
162
+ − 1282
This behaviour is not because of simplification rules, but how the subgoaler, solver
256
+ − 1283
and looper are set up in @{ML [index] HOL_basic_ss}.
157
+ − 1284
256
+ − 1285
The simpset @{ML [index] HOL_ss} is an extension of @{ML HOL_basic_ss} containing
162
+ − 1286
already many useful simplification and congruence rules for the logical
+ − 1287
connectives in HOL.
157
+ − 1288
+ − 1289
@{ML_response_fake [display,gray]
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1290
"print_ss @{context} HOL_ss"
157
+ − 1291
"Simplification rules:
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1292
Pure.triv_forall_equality: (\<And>x. PROP V) \<equiv> PROP V
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1293
HOL.the_eq_trivial: THE x. x = y \<equiv> y
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1294
HOL.the_sym_eq_trivial: THE ya. y = ya \<equiv> y
157
+ − 1295
\<dots>
+ − 1296
Congruences rules:
+ − 1297
HOL.simp_implies: \<dots>
158
d7944bdf7b3f
removed infix_conv and moved function no_vars into the FirstSteps chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1298
\<Longrightarrow> (PROP P =simp=> PROP Q) \<equiv> (PROP P' =simp=> PROP Q')
163
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1299
op -->: \<lbrakk>P \<equiv> P'; P' \<Longrightarrow> Q \<equiv> Q'\<rbrakk> \<Longrightarrow> P \<longrightarrow> Q \<equiv> P' \<longrightarrow> Q'
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1300
Simproc patterns:
2319cff107f0
removed rep_ss, and used dest_ss instead; some very slight changes to simple_inductive
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1301
\<dots>"}
157
+ − 1302
+ − 1303
162
+ − 1304
The simplifier is often used to unfold definitions in a proof. For this the
256
+ − 1305
simplifier implements the tactic @{ML [index] rewrite_goals_tac}.\footnote{FIXME:
243
+ − 1306
see LocalDefs infrastructure.} Suppose for example the
162
+ − 1307
definition
+ − 1308
*}
+ − 1309
+ − 1310
definition "MyTrue \<equiv> True"
+ − 1311
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1312
text {*
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1313
then in the following proof we can unfold this constant
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1314
*}
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1315
162
+ − 1316
lemma shows "MyTrue \<Longrightarrow> True \<and> True"
+ − 1317
apply(rule conjI)
213
+ − 1318
apply(tactic {* rewrite_goals_tac @{thms MyTrue_def} *})
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1319
txt{* producing the goal state
162
+ − 1320
+ − 1321
\begin{minipage}{\textwidth}
+ − 1322
@{subgoals [display]}
+ − 1323
\end{minipage} *}
+ − 1324
(*<*)oops(*>*)
+ − 1325
+ − 1326
text {*
+ − 1327
As you can see, the tactic unfolds the definitions in all subgoals.
153
+ − 1328
*}
+ − 1329
+ − 1330
157
+ − 1331
text_raw {*
173
+ − 1332
\begin{figure}[p]
+ − 1333
\begin{boxedminipage}{\textwidth}
157
+ − 1334
\begin{isabelle} *}
+ − 1335
types prm = "(nat \<times> nat) list"
+ − 1336
consts perm :: "prm \<Rightarrow> 'a \<Rightarrow> 'a" ("_ \<bullet> _" [80,80] 80)
+ − 1337
229
+ − 1338
overloading
+ − 1339
perm_nat \<equiv> "perm :: prm \<Rightarrow> nat \<Rightarrow> nat"
+ − 1340
perm_prod \<equiv> "perm :: prm \<Rightarrow> ('a\<times>'b) \<Rightarrow> ('a\<times>'b)"
+ − 1341
perm_list \<equiv> "perm :: prm \<Rightarrow> 'a list \<Rightarrow> 'a list"
+ − 1342
begin
+ − 1343
+ − 1344
fun swap::"nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> nat"
+ − 1345
where
+ − 1346
"swap a b c = (if c=a then b else (if c=b then a else c))"
153
+ − 1347
229
+ − 1348
primrec perm_nat
+ − 1349
where
+ − 1350
"perm_nat [] c = c"
+ − 1351
| "perm_nat (ab#pi) c = swap (fst ab) (snd ab) (perm_nat pi c)"
157
+ − 1352
229
+ − 1353
fun perm_prod
+ − 1354
where
+ − 1355
"perm_prod pi (x, y) = (pi\<bullet>x, pi\<bullet>y)"
+ − 1356
+ − 1357
primrec perm_list
+ − 1358
where
+ − 1359
"perm_list pi [] = []"
+ − 1360
| "perm_list pi (x#xs) = (pi\<bullet>x)#(perm_list pi xs)"
+ − 1361
+ − 1362
end
157
+ − 1363
+ − 1364
lemma perm_append[simp]:
229
+ − 1365
fixes c::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1366
shows "((pi\<^isub>1@pi\<^isub>2)\<bullet>c) = (pi\<^isub>1\<bullet>(pi\<^isub>2\<bullet>c))"
157
+ − 1367
by (induct pi\<^isub>1) (auto)
+ − 1368
229
+ − 1369
lemma perm_bij[simp]:
+ − 1370
fixes c d::"nat" and pi::"prm"
+ − 1371
shows "(pi\<bullet>c = pi\<bullet>d) = (c = d)"
157
+ − 1372
by (induct pi) (auto)
153
+ − 1373
157
+ − 1374
lemma perm_rev[simp]:
229
+ − 1375
fixes c::"nat" and pi::"prm"
+ − 1376
shows "pi\<bullet>((rev pi)\<bullet>c) = c"
157
+ − 1377
by (induct pi arbitrary: c) (auto)
+ − 1378
+ − 1379
lemma perm_compose:
229
+ − 1380
fixes c::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1381
shows "pi\<^isub>1\<bullet>(pi\<^isub>2\<bullet>c) = (pi\<^isub>1\<bullet>pi\<^isub>2)\<bullet>(pi\<^isub>1\<bullet>c)"
157
+ − 1382
by (induct pi\<^isub>2) (auto)
+ − 1383
text_raw {*
173
+ − 1384
\end{isabelle}
+ − 1385
\end{boxedminipage}
229
+ − 1386
\caption{A simple theory about permutations over @{typ nat}s. The point is that the
157
+ − 1387
lemma @{thm [source] perm_compose} cannot be directly added to the simplifier, as
+ − 1388
it would cause the simplifier to loop. It can still be used as a simplification
229
+ − 1389
rule if the permutation in the right-hand side is sufficiently protected.
+ − 1390
\label{fig:perms}}
157
+ − 1391
\end{figure} *}
+ − 1392
+ − 1393
+ − 1394
text {*
162
+ − 1395
The simplifier is often used in order to bring terms into a normal form.
+ − 1396
Unfortunately, often the situation arises that the corresponding
+ − 1397
simplification rules will cause the simplifier to run into an infinite
+ − 1398
loop. Consider for example the simple theory about permutations over natural
+ − 1399
numbers shown in Figure~\ref{fig:perms}. The purpose of the lemmas is to
+ − 1400
push permutations as far inside as possible, where they might disappear by
+ − 1401
Lemma @{thm [source] perm_rev}. However, to fully normalise all instances,
+ − 1402
it would be desirable to add also the lemma @{thm [source] perm_compose} to
+ − 1403
the simplifier for pushing permutations over other permutations. Unfortunately,
+ − 1404
the right-hand side of this lemma is again an instance of the left-hand side
209
+ − 1405
and so causes an infinite loop. There seems to be no easy way to reformulate
162
+ − 1406
this rule and so one ends up with clunky proofs like:
153
+ − 1407
*}
+ − 1408
157
+ − 1409
lemma
229
+ − 1410
fixes c d::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1411
shows "pi\<^isub>1\<bullet>(c, pi\<^isub>2\<bullet>((rev pi\<^isub>1)\<bullet>d)) = (pi\<^isub>1\<bullet>c, (pi\<^isub>1\<bullet>pi\<^isub>2)\<bullet>d)"
157
+ − 1412
apply(simp)
+ − 1413
apply(rule trans)
+ − 1414
apply(rule perm_compose)
+ − 1415
apply(simp)
+ − 1416
done
153
+ − 1417
+ − 1418
text {*
162
+ − 1419
It is however possible to create a single simplifier tactic that solves
157
+ − 1420
such proofs. The trick is to introduce an auxiliary constant for permutations
162
+ − 1421
and split the simplification into two phases (below actually three). Let
+ − 1422
assume the auxiliary constant is
157
+ − 1423
*}
+ − 1424
+ − 1425
definition
+ − 1426
perm_aux :: "prm \<Rightarrow> 'a \<Rightarrow> 'a" ("_ \<bullet>aux _" [80,80] 80)
+ − 1427
where
+ − 1428
"pi \<bullet>aux c \<equiv> pi \<bullet> c"
+ − 1429
162
+ − 1430
text {* Now the two lemmas *}
157
+ − 1431
+ − 1432
lemma perm_aux_expand:
229
+ − 1433
fixes c::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1434
shows "pi\<^isub>1\<bullet>(pi\<^isub>2\<bullet>c) = pi\<^isub>1 \<bullet>aux (pi\<^isub>2\<bullet>c)"
157
+ − 1435
unfolding perm_aux_def by (rule refl)
+ − 1436
+ − 1437
lemma perm_compose_aux:
229
+ − 1438
fixes c::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1439
shows "pi\<^isub>1\<bullet>(pi\<^isub>2\<bullet>aux c) = (pi\<^isub>1\<bullet>pi\<^isub>2) \<bullet>aux (pi\<^isub>1\<bullet>c)"
157
+ − 1440
unfolding perm_aux_def by (rule perm_compose)
+ − 1441
+ − 1442
text {*
+ − 1443
are simple consequence of the definition and @{thm [source] perm_compose}.
+ − 1444
More importantly, the lemma @{thm [source] perm_compose_aux} can be safely
+ − 1445
added to the simplifier, because now the right-hand side is not anymore an instance
162
+ − 1446
of the left-hand side. In a sense it freezes all redexes of permutation compositions
+ − 1447
after one step. In this way, we can split simplification of permutations
213
+ − 1448
into three phases without the user noticing anything about the auxiliary
231
+ − 1449
constant. We first freeze any instance of permutation compositions in the term using
162
+ − 1450
lemma @{thm [source] "perm_aux_expand"} (Line 9);
231
+ − 1451
then simplify all other permutations including pushing permutations over
162
+ − 1452
other permutations by rule @{thm [source] perm_compose_aux} (Line 10); and
+ − 1453
finally ``unfreeze'' all instances of permutation compositions by unfolding
+ − 1454
the definition of the auxiliary constant.
153
+ − 1455
*}
+ − 1456
157
+ − 1457
ML %linenosgray{*val perm_simp_tac =
+ − 1458
let
+ − 1459
val thms1 = [@{thm perm_aux_expand}]
229
+ − 1460
val thms2 = [@{thm perm_append}, @{thm perm_bij}, @{thm perm_rev},
157
+ − 1461
@{thm perm_compose_aux}] @ @{thms perm_prod.simps} @
+ − 1462
@{thms perm_list.simps} @ @{thms perm_nat.simps}
+ − 1463
val thms3 = [@{thm perm_aux_def}]
+ − 1464
in
+ − 1465
simp_tac (HOL_basic_ss addsimps thms1)
+ − 1466
THEN' simp_tac (HOL_basic_ss addsimps thms2)
+ − 1467
THEN' simp_tac (HOL_basic_ss addsimps thms3)
+ − 1468
end*}
153
+ − 1469
152
+ − 1470
text {*
209
+ − 1471
For all three phases we have to build simpsets adding specific lemmas. As is sufficient
232
+ − 1472
for our purposes here, we can add these lemmas to @{ML HOL_basic_ss} in order to obtain
162
+ − 1473
the desired results. Now we can solve the following lemma
157
+ − 1474
*}
+ − 1475
+ − 1476
lemma
229
+ − 1477
fixes c d::"nat" and pi\<^isub>1 pi\<^isub>2::"prm"
+ − 1478
shows "pi\<^isub>1\<bullet>(c, pi\<^isub>2\<bullet>((rev pi\<^isub>1)\<bullet>d)) = (pi\<^isub>1\<bullet>c, (pi\<^isub>1\<bullet>pi\<^isub>2)\<bullet>d)"
157
+ − 1479
apply(tactic {* perm_simp_tac 1 *})
+ − 1480
done
+ − 1481
152
+ − 1482
157
+ − 1483
text {*
209
+ − 1484
in one step. This tactic can deal with most instances of normalising permutations.
+ − 1485
In order to solve all cases we have to deal with corner-cases such as the
162
+ − 1486
lemma being an exact instance of the permutation composition lemma. This can
+ − 1487
often be done easier by implementing a simproc or a conversion. Both will be
+ − 1488
explained in the next two chapters.
+ − 1489
157
+ − 1490
(FIXME: Is it interesting to say something about @{term "op =simp=>"}?)
+ − 1491
+ − 1492
(FIXME: What are the second components of the congruence rules---something to
+ − 1493
do with weak congruence constants?)
+ − 1494
+ − 1495
(FIXME: Anything interesting to say about @{ML Simplifier.clear_ss}?)
152
+ − 1496
162
+ − 1497
(FIXME: @{ML ObjectLogic.full_atomize_tac},
152
+ − 1498
@{ML ObjectLogic.rulify_tac})
+ − 1499
240
+ − 1500
(FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy)
+ − 1501
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1502
(FIXME: explain @{ML simplify} and @{ML "Simplifier.rewrite_rule"} etc.)
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1503
129
+ − 1504
*}
+ − 1505
+ − 1506
section {* Simprocs *}
+ − 1507
+ − 1508
text {*
+ − 1509
In Isabelle you can also implement custom simplification procedures, called
149
+ − 1510
\emph{simprocs}. Simprocs can be triggered by the simplifier on a specified
+ − 1511
term-pattern and rewrite a term according to a theorem. They are useful in
+ − 1512
cases where a rewriting rule must be produced on ``demand'' or when
+ − 1513
rewriting by simplification is too unpredictable and potentially loops.
129
+ − 1514
+ − 1515
To see how simprocs work, let us first write a simproc that just prints out
132
+ − 1516
the pattern which triggers it and otherwise does nothing. For this
129
+ − 1517
you can use the function:
+ − 1518
*}
+ − 1519
243
+ − 1520
ML %linenosgray{*fun fail_simproc simpset redex =
129
+ − 1521
let
+ − 1522
val ctxt = Simplifier.the_context simpset
250
ab9e09076462
some polishing; added together with Jasmin more examples to the pretty printing section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1523
val _ = writeln ("The redex: " ^ (string_of_cterm ctxt redex))
129
+ − 1524
in
+ − 1525
NONE
+ − 1526
end*}
+ − 1527
+ − 1528
text {*
+ − 1529
This function takes a simpset and a redex (a @{ML_type cterm}) as
132
+ − 1530
arguments. In Lines 3 and~4, we first extract the context from the given
129
+ − 1531
simpset and then print out a message containing the redex. The function
+ − 1532
returns @{ML NONE} (standing for an optional @{ML_type thm}) since at the
+ − 1533
moment we are \emph{not} interested in actually rewriting anything. We want
130
+ − 1534
that the simproc is triggered by the pattern @{term "Suc n"}. This can be
149
+ − 1535
done by adding the simproc to the current simpset as follows
129
+ − 1536
*}
+ − 1537
243
+ − 1538
simproc_setup %gray fail ("Suc n") = {* K fail_simproc *}
129
+ − 1539
+ − 1540
text {*
+ − 1541
where the second argument specifies the pattern and the right-hand side
232
+ − 1542
contains the code of the simproc (we have to use @{ML K} since we are ignoring
230
8def50824320
added material about OuterKeyword.keyword and OuterParse.reserved
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1543
an argument about morphisms.
130
+ − 1544
After this, the simplifier is aware of the simproc and you can test whether
131
+ − 1545
it fires on the lemma:
129
+ − 1546
*}
120
+ − 1547
129
+ − 1548
lemma shows "Suc 0 = 1"
178
fb8f22dd8ad0
adapted to latest Attrib.setup changes and more work on the simple induct chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1549
apply(simp)
129
+ − 1550
(*<*)oops(*>*)
+ − 1551
+ − 1552
text {*
213
+ − 1553
\begin{isabelle}
+ − 1554
@{text "> The redex: Suc 0"}\\
+ − 1555
@{text "> The redex: Suc 0"}\\
+ − 1556
\end{isabelle}
+ − 1557
129
+ − 1558
This will print out the message twice: once for the left-hand side and
130
+ − 1559
once for the right-hand side. The reason is that during simplification the
+ − 1560
simplifier will at some point reduce the term @{term "1::nat"} to @{term "Suc
129
+ − 1561
0"}, and then the simproc ``fires'' also on that term.
+ − 1562
131
+ − 1563
We can add or delete the simproc from the current simpset by the usual
132
+ − 1564
\isacommand{declare}-statement. For example the simproc will be deleted
+ − 1565
with the declaration
129
+ − 1566
*}
+ − 1567
243
+ − 1568
declare [[simproc del: fail]]
129
+ − 1569
+ − 1570
text {*
+ − 1571
If you want to see what happens with just \emph{this} simproc, without any
243
+ − 1572
interference from other rewrite rules, you can call @{text fail}
129
+ − 1573
as follows:
+ − 1574
*}
+ − 1575
+ − 1576
lemma shows "Suc 0 = 1"
243
+ − 1577
apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [@{simproc fail}]) 1*})
129
+ − 1578
(*<*)oops(*>*)
+ − 1579
+ − 1580
text {*
131
+ − 1581
Now the message shows up only once since the term @{term "1::nat"} is
+ − 1582
left unchanged.
129
+ − 1583
178
fb8f22dd8ad0
adapted to latest Attrib.setup changes and more work on the simple induct chapter
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1584
Setting up a simproc using the command \isacommand{simproc\_setup} will
129
+ − 1585
always add automatically the simproc to the current simpset. If you do not
+ − 1586
want this, then you have to use a slightly different method for setting
243
+ − 1587
up the simproc. First the function @{ML fail_simproc} needs to be modified
129
+ − 1588
to
+ − 1589
*}
+ − 1590
243
+ − 1591
ML{*fun fail_simproc' simpset redex =
129
+ − 1592
let
+ − 1593
val ctxt = Simplifier.the_context simpset
239
+ − 1594
val _ = writeln ("The redex: " ^ (Syntax.string_of_term ctxt redex))
129
+ − 1595
in
+ − 1596
NONE
+ − 1597
end*}
+ − 1598
+ − 1599
text {*
130
+ − 1600
Here the redex is given as a @{ML_type term}, instead of a @{ML_type cterm}
+ − 1601
(therefore we printing it out using the function @{ML string_of_term in Syntax}).
149
+ − 1602
We can turn this function into a proper simproc using the function
+ − 1603
@{ML Simplifier.simproc_i}:
93
+ − 1604
*}
+ − 1605
105
+ − 1606
243
+ − 1607
ML{*val fail' =
146
+ − 1608
let
+ − 1609
val thy = @{theory}
+ − 1610
val pat = [@{term "Suc n"}]
+ − 1611
in
243
+ − 1612
Simplifier.simproc_i thy "fail_simproc'" pat (K fail_simproc')
146
+ − 1613
end*}
129
+ − 1614
+ − 1615
text {*
+ − 1616
Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}).
130
+ − 1617
The function also takes a list of patterns that can trigger the simproc.
132
+ − 1618
Now the simproc is set up and can be explicitly added using
256
+ − 1619
@{ML [index] addsimprocs} to a simpset whenever
132
+ − 1620
needed.
+ − 1621
+ − 1622
Simprocs are applied from inside to outside and from left to right. You can
+ − 1623
see this in the proof
129
+ − 1624
*}
+ − 1625
+ − 1626
lemma shows "Suc (Suc 0) = (Suc 1)"
243
+ − 1627
apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [fail']) 1*})
129
+ − 1628
(*<*)oops(*>*)
+ − 1629
+ − 1630
text {*
243
+ − 1631
The simproc @{ML fail'} prints out the sequence
129
+ − 1632
130
+ − 1633
@{text [display]
+ − 1634
"> Suc 0
+ − 1635
> Suc (Suc 0)
+ − 1636
> Suc 1"}
+ − 1637
131
+ − 1638
To see how a simproc applies a theorem, let us implement a simproc that
130
+ − 1639
rewrites terms according to the equation:
129
+ − 1640
*}
+ − 1641
+ − 1642
lemma plus_one:
+ − 1643
shows "Suc n \<equiv> n + 1" by simp
+ − 1644
+ − 1645
text {*
130
+ − 1646
Simprocs expect that the given equation is a meta-equation, however the
131
+ − 1647
equation can contain preconditions (the simproc then will only fire if the
132
+ − 1648
preconditions can be solved). To see that one has relatively precise control over
131
+ − 1649
the rewriting with simprocs, let us further assume we want that the simproc
+ − 1650
only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write
129
+ − 1651
*}
+ − 1652
131
+ − 1653
243
+ − 1654
ML{*fun plus_one_simproc ss redex =
129
+ − 1655
case redex of
+ − 1656
@{term "Suc 0"} => NONE
+ − 1657
| _ => SOME @{thm plus_one}*}
+ − 1658
+ − 1659
text {*
+ − 1660
and set up the simproc as follows.
+ − 1661
*}
+ − 1662
243
+ − 1663
ML{*val plus_one =
146
+ − 1664
let
+ − 1665
val thy = @{theory}
+ − 1666
val pat = [@{term "Suc n"}]
+ − 1667
in
243
+ − 1668
Simplifier.simproc_i thy "sproc +1" pat (K plus_one_simproc)
146
+ − 1669
end*}
129
+ − 1670
+ − 1671
text {*
132
+ − 1672
Now the simproc is set up so that it is triggered by terms
130
+ − 1673
of the form @{term "Suc n"}, but inside the simproc we only produce
+ − 1674
a theorem if the term is not @{term "Suc 0"}. The result you can see
131
+ − 1675
in the following proof
129
+ − 1676
*}
+ − 1677
+ − 1678
lemma shows "P (Suc (Suc (Suc 0))) (Suc 0)"
243
+ − 1679
apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [plus_one]) 1*})
129
+ − 1680
txt{*
131
+ − 1681
where the simproc produces the goal state
177
+ − 1682
+ − 1683
\begin{minipage}{\textwidth}
129
+ − 1684
@{subgoals[display]}
177
+ − 1685
\end{minipage}
129
+ − 1686
*}
+ − 1687
(*<*)oops(*>*)
+ − 1688
+ − 1689
text {*
133
+ − 1690
As usual with rewriting you have to worry about looping: you already have
243
+ − 1691
a loop with @{ML plus_one}, if you apply it with the default simpset (because
+ − 1692
the default simpset contains a rule which just does the opposite of @{ML plus_one},
132
+ − 1693
namely rewriting @{text [quotes] "+ 1"} to a successor). So you have to be careful
+ − 1694
in choosing the right simpset to which you add a simproc.
130
+ − 1695
132
+ − 1696
Next let us implement a simproc that replaces terms of the form @{term "Suc n"}
232
+ − 1697
with the number @{text n} increased by one. First we implement a function that
132
+ − 1698
takes a term and produces the corresponding integer value.
129
+ − 1699
*}
+ − 1700
+ − 1701
ML{*fun dest_suc_trm ((Const (@{const_name "Suc"}, _)) $ t) = 1 + dest_suc_trm t
+ − 1702
| dest_suc_trm t = snd (HOLogic.dest_number t)*}
+ − 1703
130
+ − 1704
text {*
256
+ − 1705
It uses the library function @{ML [index] dest_number in HOLogic} that transforms
130
+ − 1706
(Isabelle) terms, like @{term "0::nat"}, @{term "1::nat"}, @{term "2::nat"} and so
131
+ − 1707
on, into integer values. This function raises the exception @{ML TERM}, if
130
+ − 1708
the term is not a number. The next function expects a pair consisting of a term
131
+ − 1709
@{text t} (containing @{term Suc}s) and the corresponding integer value @{text n}.
130
+ − 1710
*}
+ − 1711
+ − 1712
ML %linenosgray{*fun get_thm ctxt (t, n) =
+ − 1713
let
+ − 1714
val num = HOLogic.mk_number @{typ "nat"} n
132
+ − 1715
val goal = Logic.mk_equals (t, num)
130
+ − 1716
in
214
+ − 1717
Goal.prove ctxt [] [] goal (K (Arith_Data.arith_tac ctxt 1))
130
+ − 1718
end*}
+ − 1719
+ − 1720
text {*
132
+ − 1721
From the integer value it generates the corresponding number term, called
+ − 1722
@{text num} (Line 3), and then generates the meta-equation @{text "t \<equiv> num"}
+ − 1723
(Line 4), which it proves by the arithmetic tactic in Line 6.
+ − 1724
219
+ − 1725
For our purpose at the moment, proving the meta-equation using @{ML
+ − 1726
arith_tac in Arith_Data} is fine, but there is also an alternative employing
+ − 1727
the simplifier with a special simpset. For the kind of lemmas we
+ − 1728
want to prove here, the simpset @{text "num_ss"} should suffice.
132
+ − 1729
*}
131
+ − 1730
132
+ − 1731
ML{*fun get_thm_alt ctxt (t, n) =
+ − 1732
let
+ − 1733
val num = HOLogic.mk_number @{typ "nat"} n
+ − 1734
val goal = Logic.mk_equals (t, num)
+ − 1735
val num_ss = HOL_ss addsimps [@{thm One_nat_def}, @{thm Let_def}] @
+ − 1736
@{thms nat_number} @ @{thms neg_simps} @ @{thms plus_nat.simps}
+ − 1737
in
+ − 1738
Goal.prove ctxt [] [] goal (K (simp_tac num_ss 1))
+ − 1739
end*}
130
+ − 1740
132
+ − 1741
text {*
+ − 1742
The advantage of @{ML get_thm_alt} is that it leaves very little room for
+ − 1743
something to go wrong; in contrast it is much more difficult to predict
219
+ − 1744
what happens with @{ML arith_tac in Arith_Data}, especially in more complicated
231
+ − 1745
circumstances. The disadvantage of @{ML get_thm_alt} is to find a simpset
132
+ − 1746
that is sufficiently powerful to solve every instance of the lemmas
+ − 1747
we like to prove. This requires careful tuning, but is often necessary in
+ − 1748
``production code''.\footnote{It would be of great help if there is another
+ − 1749
way than tracing the simplifier to obtain the lemmas that are successfully
+ − 1750
applied during simplification. Alas, there is none.}
+ − 1751
+ − 1752
Anyway, either version can be used in the function that produces the actual
+ − 1753
theorem for the simproc.
130
+ − 1754
*}
129
+ − 1755
243
+ − 1756
ML{*fun nat_number_simproc ss t =
129
+ − 1757
let
+ − 1758
val ctxt = Simplifier.the_context ss
+ − 1759
in
130
+ − 1760
SOME (get_thm ctxt (t, dest_suc_trm t))
129
+ − 1761
handle TERM _ => NONE
+ − 1762
end*}
+ − 1763
+ − 1764
text {*
243
+ − 1765
This function uses the fact that @{ML dest_suc_trm} might raise an exception
130
+ − 1766
@{ML TERM}. In this case there is nothing that can be rewritten and therefore no
131
+ − 1767
theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc
+ − 1768
on an example, you can set it up as follows:
129
+ − 1769
*}
+ − 1770
243
+ − 1771
ML{*val nat_number =
132
+ − 1772
let
+ − 1773
val thy = @{theory}
+ − 1774
val pat = [@{term "Suc n"}]
+ − 1775
in
243
+ − 1776
Simplifier.simproc_i thy "nat_number" pat (K nat_number_simproc)
132
+ − 1777
end*}
130
+ − 1778
+ − 1779
text {*
+ − 1780
Now in the lemma
+ − 1781
*}
129
+ − 1782
+ − 1783
lemma "P (Suc (Suc 2)) (Suc 99) (0::nat) (Suc 4 + Suc 0) (Suc (0 + 0))"
243
+ − 1784
apply(tactic {* simp_tac (HOL_ss addsimprocs [nat_number]) 1*})
129
+ − 1785
txt {*
130
+ − 1786
you obtain the more legible goal state
+ − 1787
177
+ − 1788
\begin{minipage}{\textwidth}
129
+ − 1789
@{subgoals [display]}
177
+ − 1790
\end{minipage}
129
+ − 1791
*}
+ − 1792
(*<*)oops(*>*)
+ − 1793
130
+ − 1794
text {*
132
+ − 1795
where the simproc rewrites all @{term "Suc"}s except in the last argument. There it cannot
130
+ − 1796
rewrite anything, because it does not know how to transform the term @{term "Suc (0 + 0)"}
+ − 1797
into a number. To solve this problem have a look at the next exercise.
+ − 1798
+ − 1799
\begin{exercise}\label{ex:addsimproc}
+ − 1800
Write a simproc that replaces terms of the form @{term "t\<^isub>1 + t\<^isub>2"} by their
+ − 1801
result. You can assume the terms are ``proper'' numbers, that is of the form
+ − 1802
@{term "0::nat"}, @{term "1::nat"}, @{term "2::nat"} and so on.
+ − 1803
\end{exercise}
+ − 1804
+ − 1805
(FIXME: We did not do anything with morphisms. Anything interesting
+ − 1806
one can say about them?)
+ − 1807
*}
129
+ − 1808
137
+ − 1809
section {* Conversions\label{sec:conversion} *}
132
+ − 1810
135
+ − 1811
text {*
145
+ − 1812
147
+ − 1813
Conversions are a thin layer on top of Isabelle's inference kernel, and
169
+ − 1814
can be viewed as a controllable, bare-bone version of Isabelle's simplifier.
147
+ − 1815
One difference between conversions and the simplifier is that the former
+ − 1816
act on @{ML_type cterm}s while the latter acts on @{ML_type thm}s.
+ − 1817
However, we will also show in this section how conversions can be applied
+ − 1818
to theorems via tactics. The type for conversions is
135
+ − 1819
*}
+ − 1820
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1821
ML{*type conv = cterm -> thm*}
135
+ − 1822
+ − 1823
text {*
147
+ − 1824
whereby the produced theorem is always a meta-equality. A simple conversion
256
+ − 1825
is the function @{ML [index] all_conv in Conv}, which maps a @{ML_type cterm} to an
147
+ − 1826
instance of the (meta)reflexivity theorem. For example:
135
+ − 1827
145
+ − 1828
@{ML_response_fake [display,gray]
146
+ − 1829
"Conv.all_conv @{cterm \"Foo \<or> Bar\"}"
+ − 1830
"Foo \<or> Bar \<equiv> Foo \<or> Bar"}
+ − 1831
256
+ − 1832
Another simple conversion is @{ML [index] no_conv in Conv} which always raises the
147
+ − 1833
exception @{ML CTERM}.
135
+ − 1834
145
+ − 1835
@{ML_response_fake [display,gray]
+ − 1836
"Conv.no_conv @{cterm True}"
+ − 1837
"*** Exception- CTERM (\"no conversion\", []) raised"}
+ − 1838
256
+ − 1839
A more interesting conversion is the function @{ML [index] beta_conversion in Thm}: it
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1840
produces a meta-equation between a term and its beta-normal form. For example
142
+ − 1841
145
+ − 1842
@{ML_response_fake [display,gray]
146
+ − 1843
"let
+ − 1844
val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
+ − 1845
val two = @{cterm \"2::nat\"}
+ − 1846
val ten = @{cterm \"10::nat\"}
+ − 1847
in
+ − 1848
Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
+ − 1849
end"
+ − 1850
"((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"}
+ − 1851
147
+ − 1852
Note that the actual response in this example is @{term "2 + 10 \<equiv> 2 + (10::nat)"},
190
+ − 1853
since the pretty-printer for @{ML_type cterm}s eta-normalises terms.
174
+ − 1854
But how we constructed the term (using the function
256
+ − 1855
@{ML [index] capply in Thm}, which is the application @{ML $} for @{ML_type cterm}s)
174
+ − 1856
ensures that the left-hand side must contain beta-redexes. Indeed
147
+ − 1857
if we obtain the ``raw'' representation of the produced theorem, we
+ − 1858
can see the difference:
+ − 1859
+ − 1860
@{ML_response [display,gray]
+ − 1861
"let
+ − 1862
val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
+ − 1863
val two = @{cterm \"2::nat\"}
+ − 1864
val ten = @{cterm \"10::nat\"}
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1865
val thm = Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
147
+ − 1866
in
243
+ − 1867
Thm.prop_of thm
147
+ − 1868
end"
+ − 1869
"Const (\"==\",\<dots>) $
+ − 1870
(Abs (\"x\",\<dots>,Abs (\"y\",\<dots>,\<dots>)) $\<dots>$\<dots>) $
+ − 1871
(Const (\"HOL.plus_class.plus\",\<dots>) $ \<dots> $ \<dots>)"}
142
+ − 1872
146
+ − 1873
The argument @{ML true} in @{ML Thm.beta_conversion} indicates that
243
+ − 1874
the right-hand side should be fully beta-normalised. If instead
147
+ − 1875
@{ML false} is given, then only a single beta-reduction is performed
+ − 1876
on the outer-most level. For example
146
+ − 1877
+ − 1878
@{ML_response_fake [display,gray]
+ − 1879
"let
+ − 1880
val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
+ − 1881
val two = @{cterm \"2::nat\"}
+ − 1882
in
+ − 1883
Thm.beta_conversion false (Thm.capply add two)
+ − 1884
end"
+ − 1885
"((\<lambda>x y. x + y) 2) \<equiv> \<lambda>y. 2 + y"}
+ − 1886
190
+ − 1887
Again, we actually see as output only the fully eta-normalised term.
146
+ − 1888
147
+ − 1889
The main point of conversions is that they can be used for rewriting
+ − 1890
@{ML_type cterm}s. To do this you can use the function @{ML
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1891
"Conv.rewr_conv"}, which expects a meta-equation as an argument. Suppose we
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1892
want to rewrite a @{ML_type cterm} according to the meta-equation:
135
+ − 1893
*}
+ − 1894
139
+ − 1895
lemma true_conj1: "True \<and> P \<equiv> P" by simp
135
+ − 1896
146
+ − 1897
text {*
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1898
You can see how this function works in the example rewriting
174
+ − 1899
@{term "True \<and> (Foo \<longrightarrow> Bar)"} to @{term "Foo \<longrightarrow> Bar"}.
139
+ − 1900
145
+ − 1901
@{ML_response_fake [display,gray]
146
+ − 1902
"let
149
+ − 1903
val ctrm = @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"}
146
+ − 1904
in
+ − 1905
Conv.rewr_conv @{thm true_conj1} ctrm
+ − 1906
end"
+ − 1907
"True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"}
139
+ − 1908
256
+ − 1909
Note, however, that the function @{ML [index] rewr_conv in Conv} only rewrites the
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1910
outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1911
exactly the
256
+ − 1912
left-hand side of the theorem, then @{ML [index] rewr_conv in Conv} fails by raising
147
+ − 1913
the exception @{ML CTERM}.
146
+ − 1914
+ − 1915
This very primitive way of rewriting can be made more powerful by
+ − 1916
combining several conversions into one. For this you can use conversion
256
+ − 1917
combinators. The simplest conversion combinator is @{ML [index] then_conv},
146
+ − 1918
which applies one conversion after another. For example
139
+ − 1919
145
+ − 1920
@{ML_response_fake [display,gray]
146
+ − 1921
"let
147
+ − 1922
val conv1 = Thm.beta_conversion false
146
+ − 1923
val conv2 = Conv.rewr_conv @{thm true_conj1}
147
+ − 1924
val ctrm = Thm.capply @{cterm \"\<lambda>x. x \<and> False\"} @{cterm \"True\"}
146
+ − 1925
in
+ − 1926
(conv1 then_conv conv2) ctrm
+ − 1927
end"
145
+ − 1928
"(\<lambda>x. x \<and> False) True \<equiv> False"}
139
+ − 1929
147
+ − 1930
where we first beta-reduce the term and then rewrite according to
149
+ − 1931
@{thm [source] true_conj1}. (Recall the problem with the pretty-printer
+ − 1932
normalising all terms.)
147
+ − 1933
256
+ − 1934
The conversion combinator @{ML [index] else_conv} tries out the
146
+ − 1935
first one, and if it does not apply, tries the second. For example
+ − 1936
145
+ − 1937
@{ML_response_fake [display,gray]
146
+ − 1938
"let
147
+ − 1939
val conv = Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv
146
+ − 1940
val ctrm1 = @{cterm \"True \<and> Q\"}
+ − 1941
val ctrm2 = @{cterm \"P \<or> (True \<and> Q)\"}
+ − 1942
in
+ − 1943
(conv ctrm1, conv ctrm2)
+ − 1944
end"
147
+ − 1945
"(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"}
146
+ − 1946
+ − 1947
Here the conversion of @{thm [source] true_conj1} only applies
+ − 1948
in the first case, but fails in the second. The whole conversion
256
+ − 1949
does not fail, however, because the combinator @{ML else_conv in Conv} will then
+ − 1950
try out @{ML all_conv in Conv}, which always succeeds.
146
+ − 1951
256
+ − 1952
The conversion combinator @{ML [index] try_conv in Conv} constructs a conversion
174
+ − 1953
which is tried out on a term, but in case of failure just does nothing.
+ − 1954
For example
+ − 1955
+ − 1956
@{ML_response_fake [display,gray]
+ − 1957
"Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) @{cterm \"True \<or> P\"}"
+ − 1958
"True \<or> P \<equiv> True \<or> P"}
+ − 1959
149
+ − 1960
Apart from the function @{ML beta_conversion in Thm}, which is able to fully
+ − 1961
beta-normalise a term, the conversions so far are restricted in that they
147
+ − 1962
only apply to the outer-most level of a @{ML_type cterm}. In what follows we
256
+ − 1963
will lift this restriction. The combinator @{ML [index] arg_conv in Conv} will apply
149
+ − 1964
the conversion to the first argument of an application, that is the term
147
+ − 1965
must be of the form @{ML "t1 $ t2" for t1 t2} and the conversion is applied
+ − 1966
to @{text t2}. For example
139
+ − 1967
145
+ − 1968
@{ML_response_fake [display,gray]
146
+ − 1969
"let
+ − 1970
val conv = Conv.rewr_conv @{thm true_conj1}
+ − 1971
val ctrm = @{cterm \"P \<or> (True \<and> Q)\"}
+ − 1972
in
+ − 1973
Conv.arg_conv conv ctrm
+ − 1974
end"
+ − 1975
"P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
139
+ − 1976
147
+ − 1977
The reason for this behaviour is that @{text "(op \<or>)"} expects two
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1978
arguments. Therefore the term must be of the form @{text "(Const \<dots> $ t1) $ t2"}. The
147
+ − 1979
conversion is then applied to @{text "t2"} which in the example above
256
+ − 1980
stands for @{term "True \<and> Q"}. The function @{ML [index] fun_conv in Conv} applies
150
+ − 1981
the conversion to the first argument of an application.
147
+ − 1982
256
+ − 1983
The function @{ML [index] abs_conv in Conv} applies a conversion under an abstraction.
147
+ − 1984
For example:
139
+ − 1985
147
+ − 1986
@{ML_response_fake [display,gray]
+ − 1987
"let
243
+ − 1988
val conv = Conv.rewr_conv @{thm true_conj1}
147
+ − 1989
val ctrm = @{cterm \"\<lambda>P. True \<and> P \<and> Foo\"}
+ − 1990
in
243
+ − 1991
Conv.abs_conv (K conv) @{context} ctrm
147
+ − 1992
end"
+ − 1993
"\<lambda>P. True \<and> P \<and> Foo \<equiv> \<lambda>P. P \<and> Foo"}
+ − 1994
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1995
Note that this conversion needs a context as an argument. The conversion that
256
+ − 1996
goes under an application is @{ML [index] combination_conv in Conv}. It expects two conversions
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1997
as arguments, each of which is applied to the corresponding ``branch'' of the
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 1998
application.
147
+ − 1999
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2000
We can now apply all these functions in a conversion that recursively
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2001
descends a term and applies a ``@{thm [source] true_conj1}''-conversion
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2002
in all possible positions.
146
+ − 2003
*}
+ − 2004
147
+ − 2005
ML %linenosgray{*fun all_true1_conv ctxt ctrm =
+ − 2006
case (Thm.term_of ctrm) of
142
+ − 2007
@{term "op \<and>"} $ @{term True} $ _ =>
+ − 2008
(Conv.arg_conv (all_true1_conv ctxt) then_conv
147
+ − 2009
Conv.rewr_conv @{thm true_conj1}) ctrm
+ − 2010
| _ $ _ => Conv.combination_conv
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2011
(all_true1_conv ctxt) (all_true1_conv ctxt) ctrm
147
+ − 2012
| Abs _ => Conv.abs_conv (fn (_, ctxt) => all_true1_conv ctxt) ctxt ctrm
+ − 2013
| _ => Conv.all_conv ctrm*}
139
+ − 2014
+ − 2015
text {*
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2016
This function ``fires'' if the terms is of the form @{text "True \<and> \<dots>"};
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2017
it descends under applications (Line 6 and 7) and abstractions
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2018
(Line 8); otherwise it leaves the term unchanged (Line 9). In Line 2
149
+ − 2019
we need to transform the @{ML_type cterm} into a @{ML_type term} in order
+ − 2020
to be able to pattern-match the term. To see this
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2021
conversion in action, consider the following example:
139
+ − 2022
147
+ − 2023
@{ML_response_fake [display,gray]
+ − 2024
"let
+ − 2025
val ctxt = @{context}
+ − 2026
val ctrm = @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}
+ − 2027
in
+ − 2028
all_true1_conv ctxt ctrm
+ − 2029
end"
145
+ − 2030
"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
139
+ − 2031
149
+ − 2032
To see how much control you have about rewriting by using conversions, let us
147
+ − 2033
make the task a bit more complicated by rewriting according to the rule
149
+ − 2034
@{text true_conj1}, but only in the first arguments of @{term If}s. Then
147
+ − 2035
the conversion should be as follows.
135
+ − 2036
*}
+ − 2037
147
+ − 2038
ML{*fun if_true1_conv ctxt ctrm =
+ − 2039
case Thm.term_of ctrm of
142
+ − 2040
Const (@{const_name If}, _) $ _ =>
147
+ − 2041
Conv.arg_conv (all_true1_conv ctxt) ctrm
+ − 2042
| _ $ _ => Conv.combination_conv
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2043
(if_true1_conv ctxt) (if_true1_conv ctxt) ctrm
147
+ − 2044
| Abs _ => Conv.abs_conv (fn (_, ctxt) => if_true1_conv ctxt) ctxt ctrm
+ − 2045
| _ => Conv.all_conv ctrm *}
135
+ − 2046
139
+ − 2047
text {*
149
+ − 2048
Here is an example for this conversion:
139
+ − 2049
145
+ − 2050
@{ML_response_fake [display,gray]
147
+ − 2051
"let
+ − 2052
val ctxt = @{context}
+ − 2053
val ctrm =
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2054
@{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}
147
+ − 2055
in
+ − 2056
if_true1_conv ctxt ctrm
+ − 2057
end"
+ − 2058
"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False
+ − 2059
\<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"}
135
+ − 2060
*}
+ − 2061
+ − 2062
text {*
147
+ − 2063
So far we only applied conversions to @{ML_type cterm}s. Conversions can, however,
256
+ − 2064
also work on theorems using the function @{ML [index] fconv_rule in Conv}. As an example,
149
+ − 2065
consider the conversion @{ML all_true1_conv} and the lemma:
147
+ − 2066
*}
+ − 2067
+ − 2068
lemma foo_test: "P \<or> (True \<and> \<not>P)" by simp
+ − 2069
+ − 2070
text {*
+ − 2071
Using the conversion you can transform this theorem into a new theorem
+ − 2072
as follows
+ − 2073
+ − 2074
@{ML_response_fake [display,gray]
+ − 2075
"Conv.fconv_rule (all_true1_conv @{context}) @{thm foo_test}"
+ − 2076
"?P \<or> \<not> ?P"}
+ − 2077
+ − 2078
Finally, conversions can also be turned into tactics and then applied to
256
+ − 2079
goal states. This can be done with the help of the function @{ML [index] CONVERSION},
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2080
and also some predefined conversion combinators that traverse a goal
256
+ − 2081
state. The combinators for the goal state are: @{ML [index] params_conv in Conv} for
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2082
converting under parameters (i.e.~where goals are of the form @{text "\<And>x. P \<Longrightarrow>
256
+ − 2083
Q"}); the function @{ML [index] prems_conv in Conv} for applying a conversion to all
+ − 2084
premises of a goal, and @{ML [index] concl_conv in Conv} for applying a conversion to
147
+ − 2085
the conclusion of a goal.
139
+ − 2086
145
+ − 2087
Assume we want to apply @{ML all_true1_conv} only in the conclusion
160
cc9359bfacf4
redefined the functions warning and tracing in order to properly match more antiquotations
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2088
of the goal, and @{ML if_true1_conv} should only apply to the premises.
145
+ − 2089
Here is a tactic doing exactly that:
135
+ − 2090
*}
+ − 2091
243
+ − 2092
ML{*fun true1_tac ctxt =
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2093
CONVERSION
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2094
(Conv.params_conv ~1 (fn ctxt =>
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2095
(Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv
243
+ − 2096
Conv.concl_conv ~1 (all_true1_conv ctxt))) ctxt)*}
142
+ − 2097
+ − 2098
text {*
148
+ − 2099
We call the conversions with the argument @{ML "~1"}. This is to
+ − 2100
analyse all parameters, premises and conclusions. If we call them with
147
+ − 2101
a non-negative number, say @{text n}, then these conversions will
+ − 2102
only be called on @{text n} premises (similar for parameters and
+ − 2103
conclusions). To test the tactic, consider the proof
142
+ − 2104
*}
139
+ − 2105
142
+ − 2106
lemma
+ − 2107
"if True \<and> P then P else True \<and> False \<Longrightarrow>
148
+ − 2108
(if True \<and> Q then True \<and> Q else P) \<longrightarrow> True \<and> (True \<and> Q)"
186
371e4375c994
made the Ackermann function example safer and included suggestions from MW
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2109
apply(tactic {* true1_tac @{context} 1 *})
147
+ − 2110
txt {* where the tactic yields the goal state
+ − 2111
177
+ − 2112
\begin{minipage}{\textwidth}
+ − 2113
@{subgoals [display]}
+ − 2114
\end{minipage}*}
142
+ − 2115
(*<*)oops(*>*)
135
+ − 2116
+ − 2117
text {*
148
+ − 2118
As you can see, the premises are rewritten according to @{ML if_true1_conv}, while
+ − 2119
the conclusion according to @{ML all_true1_conv}.
+ − 2120
243
+ − 2121
To sum up this section, conversions are more general than the simplifier
+ − 2122
or simprocs, but you have to do more work yourself. Also conversions are
+ − 2123
often much less efficient than the simplifier. The advantage of conversions,
+ − 2124
however, that they provide much less room for non-termination.
146
+ − 2125
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2126
\begin{exercise}\label{ex:addconversion}
152
+ − 2127
Write a tactic that does the same as the simproc in exercise
+ − 2128
\ref{ex:addsimproc}, but is based in conversions. That means replace terms
+ − 2129
of the form @{term "t\<^isub>1 + t\<^isub>2"} by their result. You can make
166
+ − 2130
the same assumptions as in \ref{ex:addsimproc}.
152
+ − 2131
\end{exercise}
+ − 2132
172
+ − 2133
\begin{exercise}\label{ex:compare}
174
+ − 2134
Compare your solutions of Exercises~\ref{ex:addsimproc} and \ref{ex:addconversion},
172
+ − 2135
and try to determine which way of rewriting such terms is faster. For this you might
+ − 2136
have to construct quite large terms. Also see Recipe \ref{rec:timing} for information
+ − 2137
about timing.
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2138
\end{exercise}
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2139
146
+ − 2140
\begin{readmore}
+ − 2141
See @{ML_file "Pure/conv.ML"} for more information about conversion combinators.
243
+ − 2142
Some basic conversions are defined in @{ML_file "Pure/thm.ML"},
146
+ − 2143
@{ML_file "Pure/drule.ML"} and @{ML_file "Pure/meta_simplifier.ML"}.
+ − 2144
\end{readmore}
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2145
135
+ − 2146
*}
+ − 2147
184
+ − 2148
text {*
+ − 2149
(FIXME: check whether @{ML Pattern.match_rew} and @{ML Pattern.rewrite_term}
+ − 2150
are of any use/efficient)
+ − 2151
*}
135
+ − 2152
151
7e0bf13bf743
added more material to the attribute section; merged the recipe about named theorems into the main body; added a solution to an exercise in the conversion section
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2153
216
+ − 2154
section {* Declarations (TBD) *}
+ − 2155
152
+ − 2156
section {* Structured Proofs (TBD) *}
95
+ − 2157
129
+ − 2158
text {* TBD *}
+ − 2159
95
+ − 2160
lemma True
+ − 2161
proof
+ − 2162
+ − 2163
{
+ − 2164
fix A B C
+ − 2165
assume r: "A & B \<Longrightarrow> C"
+ − 2166
assume A B
+ − 2167
then have "A & B" ..
+ − 2168
then have C by (rule r)
+ − 2169
}
+ − 2170
+ − 2171
{
+ − 2172
fix A B C
+ − 2173
assume r: "A & B \<Longrightarrow> C"
+ − 2174
assume A B
+ − 2175
note conjI [OF this]
+ − 2176
note r [OF this]
+ − 2177
}
+ − 2178
oops
+ − 2179
+ − 2180
ML {*
+ − 2181
val ctxt0 = @{context};
+ − 2182
val ctxt = ctxt0;
+ − 2183
val (_, ctxt) = Variable.add_fixes ["A", "B", "C"] ctxt;
217
+ − 2184
val ([r], ctxt) = Assumption.add_assumes [@{cprop "A & B \<Longrightarrow> C"}] ctxt
+ − 2185
val (this, ctxt) = Assumption.add_assumes [@{cprop "A"}, @{cprop "B"}] ctxt;
95
+ − 2186
val this = [@{thm conjI} OF this];
+ − 2187
val this = r OF this;
+ − 2188
val this = Assumption.export false ctxt ctxt0 this
+ − 2189
val this = Variable.export ctxt ctxt0 [this]
+ − 2190
*}
93
+ − 2191
+ − 2192
102
5e309df58557
general cleaning up; deleted antiquotation ML_text; adjusted pathnames of various files in the distribution
Christian Urban <urbanc@in.tum.de>
diff
changeset
+ − 2193
139
+ − 2194
end