27 |
26 |
28 text {* |
27 text {* |
29 The easiest and quickest way to include code in a theory is |
28 The easiest and quickest way to include code in a theory is |
30 by using the \isacommand{ML}-command. For example\smallskip |
29 by using the \isacommand{ML}-command. For example\smallskip |
31 |
30 |
|
31 \begin{isabelle} |
|
32 \begin{graybox} |
32 \isa{\isacommand{ML} |
33 \isa{\isacommand{ML} |
33 \isacharverbatimopen\isanewline |
34 \isacharverbatimopen\isanewline |
34 \hspace{5mm}@{ML "3 + 4"}\isanewline |
35 \hspace{5mm}@{ML "3 + 4"}\isanewline |
35 \isacharverbatimclose\isanewline |
36 \isacharverbatimclose\isanewline |
36 @{text "> 7"}\smallskip} |
37 @{text "> 7"}\smallskip} |
37 |
38 \end{graybox} |
38 The @{text [quotes] "> 7"} indicates the response Isabelle prints out when the |
39 \end{isabelle} |
39 \isacommand{ML}-command is evaluated. Like ``normal'' Isabelle proof scripts, |
40 |
|
41 Like ``normal'' Isabelle proof scripts, |
40 \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of |
42 \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of |
41 your Isabelle environment. The code inside the \isacommand{ML}-command |
43 your Isabelle environment. The code inside the \isacommand{ML}-command |
42 can also contain value and function bindings, and even those can be |
44 can also contain value and function bindings, and even those can be |
43 undone when the proof script is retracted. For better readability, we will in what |
45 undone when the proof script is retracted. As mentioned earlier, we will |
44 follows drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} |
46 drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} |
45 whenever we show code and its response. |
47 whenever we show code and its response. |
46 |
48 |
47 Once a portion of code is relatively stable, one usually wants to |
49 Once a portion of code is relatively stable, one usually wants to |
48 export it to a separate ML-file. Such files can then be included in a |
50 export it to a separate ML-file. Such files can then be included in a |
49 theory by using \isacommand{uses} in the header of the theory, like |
51 theory by using \isacommand{uses} in the header of the theory, like |
71 @{ML_response_fake [display,gray] "warning \"any string\"" "\"any string\""} |
73 @{ML_response_fake [display,gray] "warning \"any string\"" "\"any string\""} |
72 |
74 |
73 will print out @{text [quotes] "any string"} inside the response buffer |
75 will print out @{text [quotes] "any string"} inside the response buffer |
74 of Isabelle. This function expects a string as argument. If you develop under PolyML, |
76 of Isabelle. This function expects a string as argument. If you develop under PolyML, |
75 then there is a convenient, though again ``quick-and-dirty'', method for |
77 then there is a convenient, though again ``quick-and-dirty'', method for |
76 converting values into strings, namely @{ML makestring}: |
78 converting values into strings, namely using the function @{ML makestring}: |
77 |
79 |
78 @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} |
80 @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} |
79 |
81 |
80 However @{ML makestring} only works if the type of what is converted is monomorphic |
82 However @{ML makestring} only works if the type of what is converted is monomorphic |
81 and is not a function. |
83 and is not a function. |
143 function is called. Operationally speaking, the antiquotation @{text "@{theory}"} is |
152 function is called. Operationally speaking, the antiquotation @{text "@{theory}"} is |
144 \emph{not} replaced with code that will look up the current theory in |
153 \emph{not} replaced with code that will look up the current theory in |
145 some data structure and return it. Instead, it is literally |
154 some data structure and return it. Instead, it is literally |
146 replaced with the value representing the theory name. |
155 replaced with the value representing the theory name. |
147 |
156 |
148 In a similar way you can use antiquotations to refer to theorems or simpsets: |
157 In a similar way you can use antiquotations to refer to theorems: |
149 |
158 |
150 @{ML_response_fake [display,gray] "@{thm allI}" "(\<And>x. ?P x) \<Longrightarrow> \<forall>x. ?P x"} |
159 @{ML_response_fake [display,gray] "@{thm allI}" "(\<And>x. ?P x) \<Longrightarrow> \<forall>x. ?P x"} |
|
160 |
|
161 or simpsets: |
|
162 |
151 @{ML_response_fake [display,gray] |
163 @{ML_response_fake [display,gray] |
152 "let |
164 "let |
153 val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset} |
165 val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset} |
154 in |
166 in |
155 map #name (Net.entries rules) |
167 map #name (Net.entries rules) |
156 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
168 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
157 |
169 |
158 The second example extracts the theorem names that are stored in a simpset. |
170 The code above extracts the theorem names that are stored in a simpset. |
159 For this the function @{ML rep_ss in MetaSimplifier} returns a record |
171 We refer to the current simpset with the antiquotation @{text "@{simpset}"}. |
160 containing information about the simpset. The rules of a simpset are stored |
172 The function @{ML rep_ss in MetaSimplifier} returns a record |
|
173 containing all information about the simpset. The rules of a simpset are stored |
161 in a discrimination net (a datastructure for fast indexing). From this net |
174 in a discrimination net (a datastructure for fast indexing). From this net |
162 we can extract the entries using the function @{ML Net.entries}. |
175 we can extract the entries using the function @{ML Net.entries}. |
163 |
176 |
164 While antiquotations have many applications, they were originally introduced to |
177 \begin{readmore} |
165 avoid explicit bindings for theorems such as |
178 The infrastructure for simpsets is implemented in @{ML_file "Pure/meta_simplifier.ML"} |
|
179 and @{ML_file "Pure/simplifier.ML"}. |
|
180 \end{readmore} |
|
181 |
|
182 While antiquotations have many applications, they were originally introduced in order |
|
183 to avoid explicit bindings for theorems such as |
166 *} |
184 *} |
167 |
185 |
168 ML{*val allI = thm "allI" *} |
186 ML{*val allI = thm "allI" *} |
169 |
187 |
170 text {* |
188 text {* |
171 These bindings were difficult to maintain and also could accidentally |
189 These bindings were difficult to maintain and also could be accidentally |
172 be overwritten by the user. This usually broke definitional |
190 overwritten by the user. This usually broke definitional |
173 packages. Antiquotations solve this problem, since they are ``linked'' |
191 packages. Antiquotations solve this problem, since they are ``linked'' |
174 statically at compile-time. However, that also sometimes limits their |
192 statically at compile-time. However, this static linkage also limits their |
175 usefulness. In the course of this introduction, we will learn more about |
193 usefulness in cases where data needs to be build up dynamically. In the course of |
|
194 this introduction, we will learn more about |
176 these antiquotations: they greatly simplify Isabelle programming since one |
195 these antiquotations: they greatly simplify Isabelle programming since one |
177 can directly access all kinds of logical elements from ML. |
196 can directly access all kinds of logical elements from ML. |
178 |
197 |
179 *} |
198 *} |
180 |
199 |
183 text {* |
202 text {* |
184 One way to construct terms of Isabelle on the ML-level is by using the antiquotation |
203 One way to construct terms of Isabelle on the ML-level is by using the antiquotation |
185 \mbox{@{text "@{term \<dots>}"}}. For example |
204 \mbox{@{text "@{term \<dots>}"}}. For example |
186 |
205 |
187 @{ML_response [display,gray] |
206 @{ML_response [display,gray] |
188 "@{term \"(a::nat) + b = c\"}" |
207 "@{term \"(a::nat) + b = c\"}" |
189 "Const (\"op =\", \<dots>) $ (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
208 "Const (\"op =\", \<dots>) $ |
|
209 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
190 |
210 |
191 This will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
211 This will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
192 representation of this term. This internal representation corresponds to the |
212 representation of this term. This internal representation corresponds to the |
193 datatype @{ML_type "term"}. |
213 datatype @{ML_type "term"}. |
194 |
214 |
276 |
297 |
277 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *} |
298 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *} |
278 |
299 |
279 text {* |
300 text {* |
280 To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} |
301 To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} |
281 to both functions. With @{ML make_imp} we obtain the correct term involving |
302 to both functions. With @{ML make_imp} we obtain the intended term involving |
282 @{term "S"}, @{text "T"} and @{text "@{typ nat}"} |
303 @{term "S"}, @{text "T"} and @{text "@{typ nat}"} |
283 |
304 |
284 @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" |
305 @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" |
285 "Const \<dots> $ |
306 "Const \<dots> $ |
286 Abs (\"x\", Type (\"nat\",[]), |
307 Abs (\"x\", Type (\"nat\",[]), |
287 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
308 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ |
288 (Free (\"T\",\<dots>) $ \<dots>))"} |
309 (Free (\"T\",\<dots>) $ \<dots>))"} |
289 |
310 |
290 With @{ML make_wrong_imp} we obtain an incorrect term involving the @{term "P"} |
311 With @{ML make_wrong_imp} we obtain a term involving the @{term "P"} |
291 and @{text "Q"} from the antiquotation. |
312 and @{text "Q"} from the antiquotation. |
292 |
313 |
293 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" |
314 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" |
294 "Const \<dots> $ |
315 "Const \<dots> $ |
295 Abs (\"x\", \<dots>, |
316 Abs (\"x\", \<dots>, |
465 @{ML_file "Pure/thm.ML"}. |
483 @{ML_file "Pure/thm.ML"}. |
466 \end{readmore} |
484 \end{readmore} |
467 |
485 |
468 *} |
486 *} |
469 |
487 |
470 |
488 section {* Storing Theorems *} |
471 section {* Tactical Reasoning *} |
489 |
472 |
490 section {* Theorem Attributes *} |
473 text {* |
491 |
474 The goal-oriented tactical style reasoning of the ML level is similar |
492 section {* Operations on Constants (Names) *} |
475 to the @{text apply}-style at the user level, i.e.~the reasoning is centred |
493 |
476 around a \emph{goal}, which is modified in a sequence of proof steps |
494 text {* |
477 until it is solved. |
495 (FIXME how can I extract the constant name without the theory name etc) |
478 |
496 *} |
479 A goal (or goal state) is a special @{ML_type thm}, which by |
497 |
480 convention is an implication of the form: |
498 section {* Combinators\label{sec:combinators} *} |
481 |
499 |
482 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #(C)"} |
500 text {* |
483 |
501 Perhaps one of the most puzzling aspects for a beginner when reading at |
484 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the open |
502 existing Isabelle code is the liberal use of combinators. At first they |
485 subgoals. |
503 seem to obstruct the comprehension of the code, but after getting familiar |
486 Since the goal @{term C} can potentially be an implication, there is a |
504 with them they actually ease the reading and also the programming. |
487 @{text "#"} wrapped around it, which prevents that premises are |
505 |
488 misinterpreted as open subgoals. The wrapper @{text "# :: prop \<Rightarrow> |
|
489 prop"} is just the identity function and used as a syntactic marker. |
|
490 |
|
491 \begin{readmore} |
506 \begin{readmore} |
492 For more on goals see \isccite{sec:tactical-goals}. (FIXME: in which |
507 The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"} |
493 file is most code for dealing with goals?) |
|
494 \end{readmore} |
|
495 |
|
496 Tactics are functions that map a goal state to a (lazy) |
|
497 sequence of successor states, hence the type of a tactic is |
|
498 |
|
499 @{ML_type[display] "thm -> thm Seq.seq"} |
|
500 |
|
501 \begin{readmore} |
|
502 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
|
503 sequences. However in day-to-day Isabelle programming, one rarely |
|
504 constructs sequences explicitly, but uses the predefined tactic |
|
505 combinators (tacticals) instead. See @{ML_file "Pure/tctical.ML"} |
|
506 for the code; see Chapters 3 and 4 in the old Isabelle Reference Manual. |
|
507 \end{readmore} |
|
508 |
|
509 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
|
510 are expected to leave the conclusion @{term C} intact, with the |
|
511 exception of possibly instantiating schematic variables. |
|
512 |
|
513 To see how tactics work, let us transcribe a simple @{text apply}-style |
|
514 proof into ML: |
|
515 *} |
|
516 |
|
517 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P" |
|
518 apply (erule disjE) |
|
519 apply (rule disjI2) |
|
520 apply assumption |
|
521 apply (rule disjI1) |
|
522 apply assumption |
|
523 done |
|
524 |
|
525 text {* |
|
526 To start the proof, the function @{ML "Goal.prove"}~@{text "ctxt xs As C tac"} sets |
|
527 up a goal state for proving the goal @{text C} under the assumptions @{text As} |
|
528 (empty in the proof at hand) |
|
529 with the variables @{text xs} that will be generalised once the |
|
530 goal is proved. The @{text "tac"} is the tactic which proves the goal and which |
|
531 can make use of the local assumptions (there are none in this example). |
|
532 |
|
533 @{ML_response_fake [display,gray] |
|
534 "let |
|
535 val ctxt = @{context} |
|
536 val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"} |
|
537 in |
|
538 Goal.prove ctxt [\"P\", \"Q\"] [] goal (fn _ => |
|
539 eresolve_tac [disjE] 1 |
|
540 THEN resolve_tac [disjI2] 1 |
|
541 THEN assume_tac 1 |
|
542 THEN resolve_tac [disjI1] 1 |
|
543 THEN assume_tac 1) |
|
544 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
|
545 |
|
546 \begin{readmore} |
|
547 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} and |
|
548 the file @{ML_file "Pure/goal.ML"}. |
|
549 \end{readmore} |
|
550 |
|
551 |
|
552 An alternative way to transcribe this proof is as follows |
|
553 |
|
554 @{ML_response_fake [display,gray] |
|
555 "let |
|
556 val ctxt = @{context} |
|
557 val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"} |
|
558 in |
|
559 Goal.prove ctxt [\"P\", \"Q\"] [] goal (fn _ => |
|
560 (eresolve_tac [disjE] |
|
561 THEN' resolve_tac [disjI2] |
|
562 THEN' assume_tac |
|
563 THEN' resolve_tac [disjI1] |
|
564 THEN' assume_tac) 1) |
|
565 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
|
566 |
|
567 (FIXME: are there any advantages/disadvantages about this way?) |
|
568 *} |
|
569 |
|
570 section {* Storing Theorems *} |
|
571 |
|
572 section {* Theorem Attributes *} |
|
573 |
|
574 |
|
575 section {* Combinators *} |
|
576 |
|
577 text {* |
|
578 Perhaps one of the most puzzling aspects for a beginner when looking at |
|
579 existing Isabelle code is the liberal use of combinators. At first they |
|
580 seem to obstruct reading the code, but after getting familiar with them |
|
581 they actually ease the reading and also the programming. |
|
582 |
|
583 \begin{readmore} |
|
584 The most frequently used combinator are defined in @{ML_file "Pure/library.ML"} |
|
585 and @{ML_file "Pure/General/basics.ML"}. |
508 and @{ML_file "Pure/General/basics.ML"}. |
586 \end{readmore} |
509 \end{readmore} |
587 |
510 |
588 The simplest combinator is @{ML I} which is just the identidy function. |
511 The simplest combinator is @{ML I} which is just the identidy function. |
589 *} |
512 *} |
590 |
513 |
591 ML{*fun I x = x*} |
514 ML{*fun I x = x*} |
592 |
515 |
593 text {* |
516 text {* Another frequently used combinator is @{ML K} *} |
594 Another frequently used combinator is @{ML K} |
517 |
595 |
518 ML{*fun K x = fn _ => x*} |
596 |
519 |
597 *} |
520 text {* |
|
521 which ``wraps'' a function around the argument @{text "x"}. This function |
|
522 ignores its argument. |
|
523 |
|
524 @{ML "(op |>)"} |
|
525 *} |
|
526 |
|
527 ML{*fun x |> f = f x*} |
598 |
528 |
599 end |
529 end |