15 Isabelle is built around a few central ideas. One central idea is the |
15 Isabelle is built around a few central ideas. One central idea is the |
16 LCF-approach to theorem proving \cite{GordonMilnerWadsworth79} where there |
16 LCF-approach to theorem proving \cite{GordonMilnerWadsworth79} where there |
17 is a small trusted core and everything else is built on top of this trusted |
17 is a small trusted core and everything else is built on top of this trusted |
18 core. The fundamental data structures involved in this core are certified |
18 core. The fundamental data structures involved in this core are certified |
19 terms and certified types, as well as theorems. |
19 terms and certified types, as well as theorems. |
20 *} |
20 \<close> |
21 |
21 |
22 |
22 |
23 section {* Terms and Types *} |
23 section \<open>Terms and Types\<close> |
24 |
24 |
25 text {* |
25 text \<open> |
26 In Isabelle, there are certified terms and uncertified terms (respectively types). |
26 In Isabelle, there are certified terms and uncertified terms (respectively types). |
27 Uncertified terms are often just called terms. One way to construct them is by |
27 Uncertified terms are often just called terms. One way to construct them is by |
28 using the antiquotation \mbox{@{text "@{term \<dots>}"}}. For example |
28 using the antiquotation \mbox{\<open>@{term \<dots>}\<close>}. For example |
29 |
29 |
30 @{ML_response [display,gray] |
30 @{ML_response [display,gray] |
31 "@{term \"(a::nat) + b = c\"}" |
31 "@{term \"(a::nat) + b = c\"}" |
32 "Const (\"HOL.eq\", \<dots>) $ |
32 "Const (\"HOL.eq\", \<dots>) $ |
33 (Const (\"Groups.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
33 (Const (\"Groups.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
34 |
34 |
35 constructs the term @{term "(a::nat) + b = c"}. The resulting term is printed using |
35 constructs the term @{term "(a::nat) + b = c"}. The resulting term is printed using |
36 the internal representation corresponding to the datatype @{ML_type_ind "term"}, |
36 the internal representation corresponding to the datatype @{ML_type_ind "term"}, |
37 which is defined as follows: |
37 which is defined as follows: |
38 *} |
38 \<close> |
39 |
39 |
40 ML_val %linenosgray{*datatype term = |
40 ML_val %linenosgray\<open>datatype term = |
41 Const of string * typ |
41 Const of string * typ |
42 | Free of string * typ |
42 | Free of string * typ |
43 | Var of indexname * typ |
43 | Var of indexname * typ |
44 | Bound of int |
44 | Bound of int |
45 | Abs of string * typ * term |
45 | Abs of string * typ * term |
46 | $ of term * term *} |
46 | $ of term * term\<close> |
47 |
47 |
48 text {* |
48 text \<open> |
49 This datatype implements Church-style lambda-terms, where types are |
49 This datatype implements Church-style lambda-terms, where types are |
50 explicitly recorded in variables, constants and abstractions. The |
50 explicitly recorded in variables, constants and abstractions. The |
51 important point of having terms is that you can pattern-match against them; |
51 important point of having terms is that you can pattern-match against them; |
52 this cannot be done with certified terms. As can be seen in Line 5, |
52 this cannot be done with certified terms. As can be seen in Line 5, |
53 terms use the usual de Bruijn index mechanism for representing bound |
53 terms use the usual de Bruijn index mechanism for representing bound |
195 @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" |
195 @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" |
196 "(Const (\"Pure.imp\", \<dots>) $ \<dots> $ \<dots>, |
196 "(Const (\"Pure.imp\", \<dots>) $ \<dots> $ \<dots>, |
197 Const (\"Pure.imp\", \<dots>) $ \<dots> $ \<dots>)"} |
197 Const (\"Pure.imp\", \<dots>) $ \<dots> $ \<dots>)"} |
198 |
198 |
199 where it is not (since it is already constructed by a meta-implication). |
199 where it is not (since it is already constructed by a meta-implication). |
200 The purpose of the @{text "Trueprop"}-coercion is to embed formulae of |
200 The purpose of the \<open>Trueprop\<close>-coercion is to embed formulae of |
201 an object logic, for example HOL, into the meta-logic of Isabelle. The coercion |
201 an object logic, for example HOL, into the meta-logic of Isabelle. The coercion |
202 is needed whenever a term is constructed that will be proved as a theorem. |
202 is needed whenever a term is constructed that will be proved as a theorem. |
203 |
203 |
204 As already seen above, types can be constructed using the antiquotation |
204 As already seen above, types can be constructed using the antiquotation |
205 @{text "@{typ \<dots>}"}. For example: |
205 \<open>@{typ \<dots>}\<close>. For example: |
206 |
206 |
207 @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"} |
207 @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"} |
208 |
208 |
209 The corresponding datatype is |
209 The corresponding datatype is |
210 *} |
210 \<close> |
211 |
211 |
212 ML_val %grayML{*datatype typ = |
212 ML_val %grayML\<open>datatype typ = |
213 Type of string * typ list |
213 Type of string * typ list |
214 | TFree of string * sort |
214 | TFree of string * sort |
215 | TVar of indexname * sort *} |
215 | TVar of indexname * sort\<close> |
216 |
216 |
217 text {* |
217 text \<open> |
218 Like with terms, there is the distinction between free type |
218 Like with terms, there is the distinction between free type |
219 variables (term-constructor @{ML "TFree"}) and schematic |
219 variables (term-constructor @{ML "TFree"}) and schematic |
220 type variables (term-constructor @{ML "TVar"} and printed with |
220 type variables (term-constructor @{ML "TVar"} and printed with |
221 a leading question mark). A type constant, |
221 a leading question mark). A type constant, |
222 like @{typ "int"} or @{typ bool}, are types with an empty list |
222 like @{typ "int"} or @{typ bool}, are types with an empty list |
223 of argument types. However, it needs a bit of effort to show an |
223 of argument types. However, it needs a bit of effort to show an |
224 example, because Isabelle always pretty prints types (unlike terms). |
224 example, because Isabelle always pretty prints types (unlike terms). |
225 Using just the antiquotation @{text "@{typ \"bool\"}"} we only see |
225 Using just the antiquotation \<open>@{typ "bool"}\<close> we only see |
226 |
226 |
227 @{ML_response [display, gray] |
227 @{ML_response [display, gray] |
228 "@{typ \"bool\"}" |
228 "@{typ \"bool\"}" |
229 "bool"} |
229 "bool"} |
230 which is the pretty printed version of @{text "bool"}. However, in PolyML |
230 which is the pretty printed version of \<open>bool\<close>. However, in PolyML |
231 (version @{text "\<ge>"}5.3) it is easy to install your own pretty printer. With the |
231 (version \<open>\<ge>\<close>5.3) it is easy to install your own pretty printer. With the |
232 function below we mimic the behaviour of the usual pretty printer for |
232 function below we mimic the behaviour of the usual pretty printer for |
233 datatypes (it uses pretty-printing functions which will be explained in more |
233 datatypes (it uses pretty-printing functions which will be explained in more |
234 detail in Section~\ref{sec:pretty}). |
234 detail in Section~\ref{sec:pretty}). |
235 *} |
235 \<close> |
236 |
236 |
237 ML %grayML{*local |
237 ML %grayML\<open>local |
238 fun pp_pair (x, y) = Pretty.list "(" ")" [x, y] |
238 fun pp_pair (x, y) = Pretty.list "(" ")" [x, y] |
239 fun pp_list xs = Pretty.list "[" "]" xs |
239 fun pp_list xs = Pretty.list "[" "]" xs |
240 fun pp_str s = Pretty.str s |
240 fun pp_str s = Pretty.str s |
241 fun pp_qstr s = Pretty.quote (pp_str s) |
241 fun pp_qstr s = Pretty.quote (pp_str s) |
242 fun pp_int i = pp_str (string_of_int i) |
242 fun pp_int i = pp_str (string_of_int i) |
303 \begin{readmore} |
303 \begin{readmore} |
304 Types are described in detail in \isccite{sec:types}. Their |
304 Types are described in detail in \isccite{sec:types}. Their |
305 definition and many useful operations are implemented |
305 definition and many useful operations are implemented |
306 in @{ML_file "Pure/type.ML"}. |
306 in @{ML_file "Pure/type.ML"}. |
307 \end{readmore} |
307 \end{readmore} |
308 *} |
308 \<close> |
309 |
309 |
310 section {* Constructing Terms and Types Manually\label{sec:terms_types_manually} *} |
310 section \<open>Constructing Terms and Types Manually\label{sec:terms_types_manually}\<close> |
311 |
311 |
312 text {* |
312 text \<open> |
313 While antiquotations are very convenient for constructing terms, they can |
313 While antiquotations are very convenient for constructing terms, they can |
314 only construct fixed terms (remember they are ``linked'' at compile-time). |
314 only construct fixed terms (remember they are ``linked'' at compile-time). |
315 However, you often need to construct terms manually. For example, a |
315 However, you often need to construct terms manually. For example, a |
316 function that returns the implication @{text "\<And>(x::nat). P x \<Longrightarrow> Q x"} taking |
316 function that returns the implication \<open>\<And>(x::nat). P x \<Longrightarrow> Q x\<close> taking |
317 @{term P} and @{term Q} as arguments can only be written as: |
317 @{term P} and @{term Q} as arguments can only be written as: |
318 |
318 |
319 *} |
319 \<close> |
320 |
320 |
321 ML %grayML{*fun make_imp P Q = |
321 ML %grayML\<open>fun make_imp P Q = |
322 let |
322 let |
323 val x = Free ("x", @{typ nat}) |
323 val x = Free ("x", @{typ nat}) |
324 in |
324 in |
325 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
325 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
326 end *} |
326 end\<close> |
327 |
327 |
328 text {* |
328 text \<open> |
329 The reason is that you cannot pass the arguments @{term P} and @{term Q} |
329 The reason is that you cannot pass the arguments @{term P} and @{term Q} |
330 into an antiquotation.\footnote{At least not at the moment.} For example |
330 into an antiquotation.\footnote{At least not at the moment.} For example |
331 the following does \emph{not} work. |
331 the following does \emph{not} work. |
332 *} |
332 \<close> |
333 |
333 |
334 ML %grayML{*fun make_wrong_imp P Q = @{prop "\<And>(x::nat). P x \<Longrightarrow> Q x"} *} |
334 ML %grayML\<open>fun make_wrong_imp P Q = @{prop "\<And>(x::nat). P x \<Longrightarrow> Q x"}\<close> |
335 |
335 |
336 text {* |
336 text \<open> |
337 To see this, apply @{text "@{term S}"} and @{text "@{term T}"} |
337 To see this, apply \<open>@{term S}\<close> and \<open>@{term T}\<close> |
338 to both functions. With @{ML make_imp} you obtain the intended term involving |
338 to both functions. With @{ML make_imp} you obtain the intended term involving |
339 the given arguments |
339 the given arguments |
340 |
340 |
341 @{ML_response [display,gray] "make_imp @{term S} @{term T}" |
341 @{ML_response [display,gray] "make_imp @{term S} @{term T}" |
342 "Const \<dots> $ |
342 "Const \<dots> $ |
343 Abs (\"x\", Type (\"Nat.nat\",[]), |
343 Abs (\"x\", Type (\"Nat.nat\",[]), |
344 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"} |
344 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"} |
345 |
345 |
346 whereas with @{ML make_wrong_imp} you obtain a term involving the @{term "P"} |
346 whereas with @{ML make_wrong_imp} you obtain a term involving the @{term "P"} |
347 and @{text "Q"} from the antiquotation. |
347 and \<open>Q\<close> from the antiquotation. |
348 |
348 |
349 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T}" |
349 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T}" |
350 "Const \<dots> $ |
350 "Const \<dots> $ |
351 Abs (\"x\", \<dots>, |
351 Abs (\"x\", \<dots>, |
352 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
352 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
550 \end{readmore} |
550 \end{readmore} |
551 |
551 |
552 When constructing terms manually, there are a few subtle issues with |
552 When constructing terms manually, there are a few subtle issues with |
553 constants. They usually crop up when pattern matching terms or types, or |
553 constants. They usually crop up when pattern matching terms or types, or |
554 when constructing them. While it is perfectly ok to write the function |
554 when constructing them. While it is perfectly ok to write the function |
555 @{text is_true} as follows |
555 \<open>is_true\<close> as follows |
556 *} |
556 \<close> |
557 |
557 |
558 ML %grayML{*fun is_true @{term True} = true |
558 ML %grayML\<open>fun is_true @{term True} = true |
559 | is_true _ = false*} |
559 | is_true _ = false\<close> |
560 |
560 |
561 text {* |
561 text \<open> |
562 this does not work for picking out @{text "\<forall>"}-quantified terms. Because |
562 this does not work for picking out \<open>\<forall>\<close>-quantified terms. Because |
563 the function |
563 the function |
564 *} |
564 \<close> |
565 |
565 |
566 ML %grayML{*fun is_all (@{term All} $ _) = true |
566 ML %grayML\<open>fun is_all (@{term All} $ _) = true |
567 | is_all _ = false*} |
567 | is_all _ = false\<close> |
568 |
568 |
569 text {* |
569 text \<open> |
570 will not correctly match the formula @{prop[source] "\<forall>x::nat. P x"}: |
570 will not correctly match the formula @{prop[source] "\<forall>x::nat. P x"}: |
571 |
571 |
572 @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "false"} |
572 @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "false"} |
573 |
573 |
574 The problem is that the @{text "@term"}-antiquotation in the pattern |
574 The problem is that the \<open>@term\<close>-antiquotation in the pattern |
575 fixes the type of the constant @{term "All"} to be @{typ "('a \<Rightarrow> bool) \<Rightarrow> bool"} for |
575 fixes the type of the constant @{term "All"} to be @{typ "('a \<Rightarrow> bool) \<Rightarrow> bool"} for |
576 an arbitrary, but fixed type @{typ "'a"}. A properly working alternative |
576 an arbitrary, but fixed type @{typ "'a"}. A properly working alternative |
577 for this function is |
577 for this function is |
578 *} |
578 \<close> |
579 |
579 |
580 ML %grayML{*fun is_all (Const ("HOL.All", _) $ _) = true |
580 ML %grayML\<open>fun is_all (Const ("HOL.All", _) $ _) = true |
581 | is_all _ = false*} |
581 | is_all _ = false\<close> |
582 |
582 |
583 text {* |
583 text \<open> |
584 because now |
584 because now |
585 |
585 |
586 @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "true"} |
586 @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "true"} |
587 |
587 |
588 matches correctly (the first wildcard in the pattern matches any type and the |
588 matches correctly (the first wildcard in the pattern matches any type and the |
589 second any term). |
589 second any term). |
590 |
590 |
591 However there is still a problem: consider the similar function that |
591 However there is still a problem: consider the similar function that |
592 attempts to pick out @{text "Nil"}-terms: |
592 attempts to pick out \<open>Nil\<close>-terms: |
593 *} |
593 \<close> |
594 |
594 |
595 ML %grayML{*fun is_nil (Const ("Nil", _)) = true |
595 ML %grayML\<open>fun is_nil (Const ("Nil", _)) = true |
596 | is_nil _ = false *} |
596 | is_nil _ = false\<close> |
597 |
597 |
598 text {* |
598 text \<open> |
599 Unfortunately, also this function does \emph{not} work as expected, since |
599 Unfortunately, also this function does \emph{not} work as expected, since |
600 |
600 |
601 @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"} |
601 @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"} |
602 |
602 |
603 The problem is that on the ML-level the name of a constant is more |
603 The problem is that on the ML-level the name of a constant is more |
605 because @{term "All"} is such a fundamental constant, which can be referenced |
605 because @{term "All"} is such a fundamental constant, which can be referenced |
606 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
606 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
607 |
607 |
608 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
608 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
609 |
609 |
610 the name of the constant @{text "Nil"} depends on the theory in which the |
610 the name of the constant \<open>Nil\<close> depends on the theory in which the |
611 term constructor is defined (@{text "List"}) and also in which datatype |
611 term constructor is defined (\<open>List\<close>) and also in which datatype |
612 (@{text "list"}). Even worse, some constants have a name involving |
612 (\<open>list\<close>). Even worse, some constants have a name involving |
613 type-classes. Consider for example the constants for @{term "zero"} and |
613 type-classes. Consider for example the constants for @{term "zero"} and |
614 \mbox{@{term "times"}}: |
614 \mbox{@{term "times"}}: |
615 |
615 |
616 @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"times\"})" |
616 @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"times\"})" |
617 "(Const (\"Groups.zero_class.zero\", \<dots>), |
617 "(Const (\"Groups.zero_class.zero\", \<dots>), |
618 Const (\"Groups.times_class.times\", \<dots>))"} |
618 Const (\"Groups.times_class.times\", \<dots>))"} |
619 |
619 |
620 While you could use the complete name, for example |
620 While you could use the complete name, for example |
621 @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or |
621 @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or |
622 matching against @{text "Nil"}, this would make the code rather brittle. |
622 matching against \<open>Nil\<close>, this would make the code rather brittle. |
623 The reason is that the theory and the name of the datatype can easily change. |
623 The reason is that the theory and the name of the datatype can easily change. |
624 To make the code more robust, it is better to use the antiquotation |
624 To make the code more robust, it is better to use the antiquotation |
625 @{text "@{const_name \<dots>}"}. With this antiquotation you can harness the |
625 \<open>@{const_name \<dots>}\<close>. With this antiquotation you can harness the |
626 variable parts of the constant's name. Therefore a function for |
626 variable parts of the constant's name. Therefore a function for |
627 matching against constants that have a polymorphic type should |
627 matching against constants that have a polymorphic type should |
628 be written as follows. |
628 be written as follows. |
629 *} |
629 \<close> |
630 |
630 |
631 ML %grayML{*fun is_nil_or_all (Const (@{const_name "Nil"}, _)) = true |
631 ML %grayML\<open>fun is_nil_or_all (Const (@{const_name "Nil"}, _)) = true |
632 | is_nil_or_all (Const (@{const_name "All"}, _) $ _) = true |
632 | is_nil_or_all (Const (@{const_name "All"}, _) $ _) = true |
633 | is_nil_or_all _ = false *} |
633 | is_nil_or_all _ = false\<close> |
634 |
634 |
635 text {* |
635 text \<open> |
636 The antiquotation for properly referencing type constants is @{text "@{type_name \<dots>}"}. |
636 The antiquotation for properly referencing type constants is \<open>@{type_name \<dots>}\<close>. |
637 For example |
637 For example |
638 |
638 |
639 @{ML_response [display,gray] |
639 @{ML_response [display,gray] |
640 "@{type_name \"list\"}" "\"List.list\""} |
640 "@{type_name \"list\"}" "\"List.list\""} |
641 |
641 |
642 Although types of terms can often be inferred, there are many |
642 Although types of terms can often be inferred, there are many |
643 situations where you need to construct types manually, especially |
643 situations where you need to construct types manually, especially |
644 when defining constants. For example the function returning a function |
644 when defining constants. For example the function returning a function |
645 type is as follows: |
645 type is as follows: |
646 |
646 |
647 *} |
647 \<close> |
648 |
648 |
649 ML %grayML{*fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2]) *} |
649 ML %grayML\<open>fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2])\<close> |
650 |
650 |
651 text {* This can be equally written with the combinator @{ML_ind "-->" in Term} as: *} |
651 text \<open>This can be equally written with the combinator @{ML_ind "-->" in Term} as:\<close> |
652 |
652 |
653 ML %grayML{*fun make_fun_type ty1 ty2 = ty1 --> ty2 *} |
653 ML %grayML\<open>fun make_fun_type ty1 ty2 = ty1 --> ty2\<close> |
654 |
654 |
655 text {* |
655 text \<open> |
656 If you want to construct a function type with more than one argument |
656 If you want to construct a function type with more than one argument |
657 type, then you can use @{ML_ind "--->" in Term}. |
657 type, then you can use @{ML_ind "--->" in Term}. |
658 *} |
658 \<close> |
659 |
659 |
660 ML %grayML{*fun make_fun_types tys ty = tys ---> ty *} |
660 ML %grayML\<open>fun make_fun_types tys ty = tys ---> ty\<close> |
661 |
661 |
662 text {* |
662 text \<open> |
663 A handy function for manipulating terms is @{ML_ind map_types in Term}: it takes a |
663 A handy function for manipulating terms is @{ML_ind map_types in Term}: it takes a |
664 function and applies it to every type in a term. You can, for example, |
664 function and applies it to every type in a term. You can, for example, |
665 change every @{typ nat} in a term into an @{typ int} using the function: |
665 change every @{typ nat} in a term into an @{typ int} using the function: |
666 *} |
666 \<close> |
667 |
667 |
668 ML %grayML{*fun nat_to_int ty = |
668 ML %grayML\<open>fun nat_to_int ty = |
669 (case ty of |
669 (case ty of |
670 @{typ nat} => @{typ int} |
670 @{typ nat} => @{typ int} |
671 | Type (s, tys) => Type (s, map nat_to_int tys) |
671 | Type (s, tys) => Type (s, map nat_to_int tys) |
672 | _ => ty)*} |
672 | _ => ty)\<close> |
673 |
673 |
674 text {* |
674 text \<open> |
675 Here is an example: |
675 Here is an example: |
676 |
676 |
677 @{ML_response_fake [display,gray] |
677 @{ML_response_fake [display,gray] |
678 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
678 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
679 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
679 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
754 |
754 |
755 Make sure you use the functions defined in @{ML_file "HOL/Tools/hologic.ML"} |
755 Make sure you use the functions defined in @{ML_file "HOL/Tools/hologic.ML"} |
756 for constructing the terms for the logical connectives.\footnote{Thanks to Roy |
756 for constructing the terms for the logical connectives.\footnote{Thanks to Roy |
757 Dyckhoff for suggesting this exercise and working out the details.} |
757 Dyckhoff for suggesting this exercise and working out the details.} |
758 \end{exercise} |
758 \end{exercise} |
759 *} |
759 \<close> |
760 |
760 |
761 section {* Unification and Matching\label{sec:univ} *} |
761 section \<open>Unification and Matching\label{sec:univ}\<close> |
762 |
762 |
763 text {* |
763 text \<open> |
764 As seen earlier, Isabelle's terms and types may contain schematic term variables |
764 As seen earlier, Isabelle's terms and types may contain schematic term variables |
765 (term-constructor @{ML Var}) and schematic type variables (term-constructor |
765 (term-constructor @{ML Var}) and schematic type variables (term-constructor |
766 @{ML TVar}). These variables stand for unknown entities, which can be made |
766 @{ML TVar}). These variables stand for unknown entities, which can be made |
767 more concrete by instantiations. Such instantiations might be a result of |
767 more concrete by instantiations. Such instantiations might be a result of |
768 unification or matching. While in case of types, unification and matching is |
768 unification or matching. While in case of types, unification and matching is |
769 relatively straightforward, in case of terms the algorithms are |
769 relatively straightforward, in case of terms the algorithms are |
770 substantially more complicated, because terms need higher-order versions of |
770 substantially more complicated, because terms need higher-order versions of |
771 the unification and matching algorithms. Below we shall use the |
771 the unification and matching algorithms. Below we shall use the |
772 antiquotations @{text "@{typ_pat \<dots>}"} and @{text "@{term_pat \<dots>}"} from |
772 antiquotations \<open>@{typ_pat \<dots>}\<close> and \<open>@{term_pat \<dots>}\<close> from |
773 Section~\ref{sec:antiquote} in order to construct examples involving |
773 Section~\ref{sec:antiquote} in order to construct examples involving |
774 schematic variables. |
774 schematic variables. |
775 |
775 |
776 Let us begin with describing the unification and matching functions for |
776 Let us begin with describing the unification and matching functions for |
777 types. Both return type environments (ML-type @{ML_type "Type.tyenv"}) |
777 types. Both return type environments (ML-type @{ML_type "Type.tyenv"}) |
778 which map schematic type variables to types and sorts. Below we use the |
778 which map schematic type variables to types and sorts. Below we use the |
779 function @{ML_ind typ_unify in Sign} from the structure @{ML_struct Sign} |
779 function @{ML_ind typ_unify in Sign} from the structure @{ML_struct Sign} |
780 for unifying the types @{text "?'a * ?'b"} and @{text "?'b list * |
780 for unifying the types \<open>?'a * ?'b\<close> and \<open>?'b list * |
781 nat"}. This will produce the mapping, or type environment, @{text "[?'a := |
781 nat\<close>. This will produce the mapping, or type environment, \<open>[?'a := |
782 ?'b list, ?'b := nat]"}. |
782 ?'b list, ?'b := nat]\<close>. |
783 *} |
783 \<close> |
784 |
784 |
785 ML %linenosgray{*val (tyenv_unif, _) = let |
785 ML %linenosgray\<open>val (tyenv_unif, _) = let |
786 val ty1 = @{typ_pat "?'a * ?'b"} |
786 val ty1 = @{typ_pat "?'a * ?'b"} |
787 val ty2 = @{typ_pat "?'b list * nat"} |
787 val ty2 = @{typ_pat "?'b list * nat"} |
788 in |
788 in |
789 Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) |
789 Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) |
790 end*} |
790 end\<close> |
791 |
791 |
792 text {* |
792 text \<open> |
793 The environment @{ML_ind "Vartab.empty"} in line 5 stands for the empty type |
793 The environment @{ML_ind "Vartab.empty"} in line 5 stands for the empty type |
794 environment, which is needed for starting the unification without any |
794 environment, which is needed for starting the unification without any |
795 (pre)instantiations. The @{text 0} is an integer index that will be explained |
795 (pre)instantiations. The \<open>0\<close> is an integer index that will be explained |
796 below. In case of failure, @{ML typ_unify in Sign} will raise the exception |
796 below. In case of failure, @{ML typ_unify in Sign} will raise the exception |
797 @{text TUNIFY}. We can print out the resulting type environment bound to |
797 \<open>TUNIFY\<close>. We can print out the resulting type environment bound to |
798 @{ML tyenv_unif} with the built-in function @{ML_ind dest in Vartab} from the |
798 @{ML tyenv_unif} with the built-in function @{ML_ind dest in Vartab} from the |
799 structure @{ML_struct Vartab}. |
799 structure @{ML_struct Vartab}. |
800 |
800 |
801 @{ML_response_fake [display,gray] |
801 @{ML_response_fake [display,gray] |
802 "Vartab.dest tyenv_unif" |
802 "Vartab.dest tyenv_unif" |
803 "[((\"'a\", 0), ([\"HOL.type\"], \"?'b List.list\")), |
803 "[((\"'a\", 0), ([\"HOL.type\"], \"?'b List.list\")), |
804 ((\"'b\", 0), ([\"HOL.type\"], \"nat\"))]"} |
804 ((\"'b\", 0), ([\"HOL.type\"], \"nat\"))]"} |
805 *} |
805 \<close> |
806 |
806 |
807 text_raw {* |
807 text_raw \<open> |
808 \begin{figure}[t] |
808 \begin{figure}[t] |
809 \begin{minipage}{\textwidth} |
809 \begin{minipage}{\textwidth} |
810 \begin{isabelle}*} |
810 \begin{isabelle}\<close> |
811 ML %grayML{*fun pretty_helper aux env = |
811 ML %grayML\<open>fun pretty_helper aux env = |
812 env |> Vartab.dest |
812 env |> Vartab.dest |
813 |> map aux |
813 |> map aux |
814 |> map (fn (s1, s2) => Pretty.block [s1, Pretty.str " := ", s2]) |
814 |> map (fn (s1, s2) => Pretty.block [s1, Pretty.str " := ", s2]) |
815 |> Pretty.enum "," "[" "]" |
815 |> Pretty.enum "," "[" "]" |
816 |> pwriteln |
816 |> pwriteln |
844 "[?'a := ?'b list, ?'b := nat]"} |
844 "[?'a := ?'b list, ?'b := nat]"} |
845 |
845 |
846 The way the unification function @{ML typ_unify in Sign} is implemented |
846 The way the unification function @{ML typ_unify in Sign} is implemented |
847 using an initial type environment and initial index makes it easy to |
847 using an initial type environment and initial index makes it easy to |
848 unify more than two terms. For example |
848 unify more than two terms. For example |
849 *} |
849 \<close> |
850 |
850 |
851 ML %linenosgray{*val (tyenvs, _) = let |
851 ML %linenosgray\<open>val (tyenvs, _) = let |
852 val tys1 = (@{typ_pat "?'a"}, @{typ_pat "?'b list"}) |
852 val tys1 = (@{typ_pat "?'a"}, @{typ_pat "?'b list"}) |
853 val tys2 = (@{typ_pat "?'b"}, @{typ_pat "nat"}) |
853 val tys2 = (@{typ_pat "?'b"}, @{typ_pat "nat"}) |
854 in |
854 in |
855 fold (Sign.typ_unify @{theory}) [tys1, tys2] (Vartab.empty, 0) |
855 fold (Sign.typ_unify @{theory}) [tys1, tys2] (Vartab.empty, 0) |
856 end*} |
856 end\<close> |
857 |
857 |
858 text {* |
858 text \<open> |
859 The index @{text 0} in Line 5 is the maximal index of the schematic type |
859 The index \<open>0\<close> in Line 5 is the maximal index of the schematic type |
860 variables occurring in @{text tys1} and @{text tys2}. This index will be |
860 variables occurring in \<open>tys1\<close> and \<open>tys2\<close>. This index will be |
861 increased whenever a new schematic type variable is introduced during |
861 increased whenever a new schematic type variable is introduced during |
862 unification. This is for example the case when two schematic type variables |
862 unification. This is for example the case when two schematic type variables |
863 have different, incomparable sorts. Then a new schematic type variable is |
863 have different, incomparable sorts. Then a new schematic type variable is |
864 introduced with the combined sorts. To show this let us assume two sorts, |
864 introduced with the combined sorts. To show this let us assume two sorts, |
865 say @{text "s1"} and @{text "s2"}, which we attach to the schematic type |
865 say \<open>s1\<close> and \<open>s2\<close>, which we attach to the schematic type |
866 variables @{text "?'a"} and @{text "?'b"}. Since we do not make any |
866 variables \<open>?'a\<close> and \<open>?'b\<close>. Since we do not make any |
867 assumption about the sorts, they are incomparable. |
867 assumption about the sorts, they are incomparable. |
868 *} |
868 \<close> |
869 |
869 |
870 class s1 |
870 class s1 |
871 class s2 |
871 class s2 |
872 |
872 |
873 ML %grayML{*val (tyenv, index) = let |
873 ML %grayML\<open>val (tyenv, index) = let |
874 val ty1 = @{typ_pat "?'a::s1"} |
874 val ty1 = @{typ_pat "?'a::s1"} |
875 val ty2 = @{typ_pat "?'b::s2"} |
875 val ty2 = @{typ_pat "?'b::s2"} |
876 in |
876 in |
877 Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) |
877 Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) |
878 end*} |
878 end\<close> |
879 |
879 |
880 text {* |
880 text \<open> |
881 To print out the result type environment we switch on the printing |
881 To print out the result type environment we switch on the printing |
882 of sort information by setting @{ML_ind show_sorts in Syntax} to |
882 of sort information by setting @{ML_ind show_sorts in Syntax} to |
883 true. This allows us to inspect the typing environment. |
883 true. This allows us to inspect the typing environment. |
884 |
884 |
885 @{ML_response_fake [display,gray] |
885 @{ML_response_fake [display,gray] |
886 "pretty_tyenv @{context} tyenv" |
886 "pretty_tyenv @{context} tyenv" |
887 "[?'a::s1 := ?'a1::{s1, s2}, ?'b::s2 := ?'a1::{s1, s2}]"} |
887 "[?'a::s1 := ?'a1::{s1, s2}, ?'b::s2 := ?'a1::{s1, s2}]"} |
888 |
888 |
889 As can be seen, the type variables @{text "?'a"} and @{text "?'b"} are instantiated |
889 As can be seen, the type variables \<open>?'a\<close> and \<open>?'b\<close> are instantiated |
890 with a new type variable @{text "?'a1"} with sort @{text "{s1, s2}"}. Since a new |
890 with a new type variable \<open>?'a1\<close> with sort \<open>{s1, s2}\<close>. Since a new |
891 type variable has been introduced the @{ML index}, originally being @{text 0}, |
891 type variable has been introduced the @{ML index}, originally being \<open>0\<close>, |
892 has been increased to @{text 1}. |
892 has been increased to \<open>1\<close>. |
893 |
893 |
894 @{ML_response [display,gray] |
894 @{ML_response [display,gray] |
895 "index" |
895 "index" |
896 "1"} |
896 "1"} |
897 |
897 |
898 Let us now return to the unification problem @{text "?'a * ?'b"} and |
898 Let us now return to the unification problem \<open>?'a * ?'b\<close> and |
899 @{text "?'b list * nat"} from the beginning of this section, and the |
899 \<open>?'b list * nat\<close> from the beginning of this section, and the |
900 calculated type environment @{ML tyenv_unif}: |
900 calculated type environment @{ML tyenv_unif}: |
901 |
901 |
902 @{ML_response_fake [display, gray] |
902 @{ML_response_fake [display, gray] |
903 "pretty_tyenv @{context} tyenv_unif" |
903 "pretty_tyenv @{context} tyenv_unif" |
904 "[?'a := ?'b list, ?'b := nat]"} |
904 "[?'a := ?'b list, ?'b := nat]"} |
905 |
905 |
906 Observe that the type environment which the function @{ML typ_unify in |
906 Observe that the type environment which the function @{ML typ_unify in |
907 Sign} returns is \emph{not} an instantiation in fully solved form: while @{text |
907 Sign} returns is \emph{not} an instantiation in fully solved form: while \<open>?'b\<close> is instantiated to @{typ nat}, this is not propagated to the |
908 "?'b"} is instantiated to @{typ nat}, this is not propagated to the |
908 instantiation for \<open>?'a\<close>. In unification theory, this is often |
909 instantiation for @{text "?'a"}. In unification theory, this is often |
|
910 called an instantiation in \emph{triangular form}. These triangular |
909 called an instantiation in \emph{triangular form}. These triangular |
911 instantiations, or triangular type environments, are used because of |
910 instantiations, or triangular type environments, are used because of |
912 performance reasons. To apply such a type environment to a type, say @{text "?'a * |
911 performance reasons. To apply such a type environment to a type, say \<open>?'a * |
913 ?'b"}, you should use the function @{ML_ind norm_type in Envir}: |
912 ?'b\<close>, you should use the function @{ML_ind norm_type in Envir}: |
914 |
913 |
915 @{ML_response_fake [display, gray] |
914 @{ML_response_fake [display, gray] |
916 "Envir.norm_type tyenv_unif @{typ_pat \"?'a * ?'b\"}" |
915 "Envir.norm_type tyenv_unif @{typ_pat \"?'a * ?'b\"}" |
917 "nat list * nat"} |
916 "nat list * nat"} |
918 |
917 |
919 Matching of types can be done with the function @{ML_ind typ_match in Sign} |
918 Matching of types can be done with the function @{ML_ind typ_match in Sign} |
920 also from the structure @{ML_struct Sign}. This function returns a @{ML_type |
919 also from the structure @{ML_struct Sign}. This function returns a @{ML_type |
921 Type.tyenv} as well, but might raise the exception @{text TYPE_MATCH} in case |
920 Type.tyenv} as well, but might raise the exception \<open>TYPE_MATCH\<close> in case |
922 of failure. For example |
921 of failure. For example |
923 *} |
922 \<close> |
924 |
923 |
925 ML %grayML{*val tyenv_match = let |
924 ML %grayML\<open>val tyenv_match = let |
926 val pat = @{typ_pat "?'a * ?'b"} |
925 val pat = @{typ_pat "?'a * ?'b"} |
927 and ty = @{typ_pat "bool list * nat"} |
926 and ty = @{typ_pat "bool list * nat"} |
928 in |
927 in |
929 Sign.typ_match @{theory} (pat, ty) Vartab.empty |
928 Sign.typ_match @{theory} (pat, ty) Vartab.empty |
930 end*} |
929 end\<close> |
931 |
930 |
932 text {* |
931 text \<open> |
933 Printing out the calculated matcher gives |
932 Printing out the calculated matcher gives |
934 |
933 |
935 @{ML_response_fake [display,gray] |
934 @{ML_response_fake [display,gray] |
936 "pretty_tyenv @{context} tyenv_match" |
935 "pretty_tyenv @{context} tyenv_match" |
937 "[?'a := bool list, ?'b := nat]"} |
936 "[?'a := bool list, ?'b := nat]"} |
981 as results. These are implemented in @{ML_file "Pure/envir.ML"}. |
980 as results. These are implemented in @{ML_file "Pure/envir.ML"}. |
982 This file also includes the substitution and normalisation functions, |
981 This file also includes the substitution and normalisation functions, |
983 which apply a type environment to a type. Type environments are lookup |
982 which apply a type environment to a type. Type environments are lookup |
984 tables which are implemented in @{ML_file "Pure/term_ord.ML"}. |
983 tables which are implemented in @{ML_file "Pure/term_ord.ML"}. |
985 \end{readmore} |
984 \end{readmore} |
986 *} |
985 \<close> |
987 |
986 |
988 text {* |
987 text \<open> |
989 Unification and matching of terms is substantially more complicated than the |
988 Unification and matching of terms is substantially more complicated than the |
990 type-case. The reason is that terms have abstractions and, in this context, |
989 type-case. The reason is that terms have abstractions and, in this context, |
991 unification or matching modulo plain equality is often not meaningful. |
990 unification or matching modulo plain equality is often not meaningful. |
992 Nevertheless, Isabelle implements the function @{ML_ind |
991 Nevertheless, Isabelle implements the function @{ML_ind |
993 first_order_match in Pattern} for terms. This matching function returns a |
992 first_order_match in Pattern} for terms. This matching function returns a |
994 type environment and a term environment. To pretty print the latter we use |
993 type environment and a term environment. To pretty print the latter we use |
995 the function @{text "pretty_env"}: |
994 the function \<open>pretty_env\<close>: |
996 *} |
995 \<close> |
997 |
996 |
998 ML %grayML{*fun pretty_env ctxt env = |
997 ML %grayML\<open>fun pretty_env ctxt env = |
999 let |
998 let |
1000 fun get_trms (v, (T, t)) = (Var (v, T), t) |
999 fun get_trms (v, (T, t)) = (Var (v, T), t) |
1001 val print = apply2 (pretty_term ctxt) |
1000 val print = apply2 (pretty_term ctxt) |
1002 in |
1001 in |
1003 pretty_helper (print o get_trms) env |
1002 pretty_helper (print o get_trms) env |
1004 end*} |
1003 end\<close> |
1005 |
1004 |
1006 text {* |
1005 text \<open> |
1007 As can be seen from the @{text "get_trms"}-function, a term environment associates |
1006 As can be seen from the \<open>get_trms\<close>-function, a term environment associates |
1008 a schematic term variable with a type and a term. An example of a first-order |
1007 a schematic term variable with a type and a term. An example of a first-order |
1009 matching problem is the term @{term "P (\<lambda>a b. Q b a)"} and the pattern |
1008 matching problem is the term @{term "P (\<lambda>a b. Q b a)"} and the pattern |
1010 @{text "?X ?Y"}. |
1009 \<open>?X ?Y\<close>. |
1011 *} |
1010 \<close> |
1012 |
1011 |
1013 ML %grayML{*val (_, fo_env) = let |
1012 ML %grayML\<open>val (_, fo_env) = let |
1014 val fo_pat = @{term_pat "(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y"} |
1013 val fo_pat = @{term_pat "(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y"} |
1015 val trm_a = @{term "P::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool"} |
1014 val trm_a = @{term "P::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool"} |
1016 val trm_b = @{term "\<lambda>a b. (Q::nat\<Rightarrow>nat\<Rightarrow>nat) b a"} |
1015 val trm_b = @{term "\<lambda>a b. (Q::nat\<Rightarrow>nat\<Rightarrow>nat) b a"} |
1017 val init = (Vartab.empty, Vartab.empty) |
1016 val init = (Vartab.empty, Vartab.empty) |
1018 in |
1017 in |
1019 Pattern.first_order_match @{theory} (fo_pat, trm_a $ trm_b) init |
1018 Pattern.first_order_match @{theory} (fo_pat, trm_a $ trm_b) init |
1020 end *} |
1019 end\<close> |
1021 |
1020 |
1022 text {* |
1021 text \<open> |
1023 In this example we annotated types explicitly because then |
1022 In this example we annotated types explicitly because then |
1024 the type environment is empty and can be ignored. The |
1023 the type environment is empty and can be ignored. The |
1025 resulting term environment is |
1024 resulting term environment is |
1026 |
1025 |
1027 @{ML_response_fake [display, gray] |
1026 @{ML_response_fake [display, gray] |
1112 pretty_env @{context} (Envir.term_env env) |
1111 pretty_env @{context} (Envir.term_env env) |
1113 end" |
1112 end" |
1114 "[?X := \<lambda>y x. x, ?Y := \<lambda>x. x]"} |
1113 "[?X := \<lambda>y x. x, ?Y := \<lambda>x. x]"} |
1115 |
1114 |
1116 The function @{ML_ind "Envir.empty"} generates a record with a specified |
1115 The function @{ML_ind "Envir.empty"} generates a record with a specified |
1117 max-index for the schematic variables (in the example the index is @{text |
1116 max-index for the schematic variables (in the example the index is \<open>0\<close>) and empty type and term environments. The function @{ML_ind |
1118 0}) and empty type and term environments. The function @{ML_ind |
|
1119 "Envir.term_env"} pulls out the term environment from the result record. The |
1117 "Envir.term_env"} pulls out the term environment from the result record. The |
1120 corresponding function for type environment is @{ML_ind |
1118 corresponding function for type environment is @{ML_ind |
1121 "Envir.type_env"}. An assumption of this function is that the terms to be |
1119 "Envir.type_env"}. An assumption of this function is that the terms to be |
1122 unified have already the same type. In case of failure, the exceptions that |
1120 unified have already the same type. In case of failure, the exceptions that |
1123 are raised are either @{text Pattern}, @{text MATCH} or @{text Unif}. |
1121 are raised are either \<open>Pattern\<close>, \<open>MATCH\<close> or \<open>Unif\<close>. |
1124 |
1122 |
1125 As mentioned before, unrestricted higher-order unification, respectively |
1123 As mentioned before, unrestricted higher-order unification, respectively |
1126 unrestricted higher-order matching, is in general undecidable and might also |
1124 unrestricted higher-order matching, is in general undecidable and might also |
1127 not possess a single most general solution. Therefore Isabelle implements the |
1125 not possess a single most general solution. Therefore Isabelle implements the |
1128 unification function @{ML_ind unifiers in Unify} so that it returns a lazy |
1126 unification function @{ML_ind unifiers in Unify} so that it returns a lazy |
1129 list of potentially infinite unifiers. An example is as follows |
1127 list of potentially infinite unifiers. An example is as follows |
1130 *} |
1128 \<close> |
1131 |
1129 |
1132 ML %grayML{*val uni_seq = |
1130 ML %grayML\<open>val uni_seq = |
1133 let |
1131 let |
1134 val trm1 = @{term_pat "?X ?Y"} |
1132 val trm1 = @{term_pat "?X ?Y"} |
1135 val trm2 = @{term "f a"} |
1133 val trm2 = @{term "f a"} |
1136 val init = Envir.empty 0 |
1134 val init = Envir.empty 0 |
1137 in |
1135 in |
1138 Unify.unifiers (Context.Proof @{context}, init, [(trm1, trm2)]) |
1136 Unify.unifiers (Context.Proof @{context}, init, [(trm1, trm2)]) |
1139 end *} |
1137 end\<close> |
1140 |
1138 |
1141 text {* |
1139 text \<open> |
1142 The unifiers can be extracted from the lazy sequence using the |
1140 The unifiers can be extracted from the lazy sequence using the |
1143 function @{ML_ind "Seq.pull"}. In the example we obtain three |
1141 function @{ML_ind "Seq.pull"}. In the example we obtain three |
1144 unifiers @{text "un1\<dots>un3"}. |
1142 unifiers \<open>un1\<dots>un3\<close>. |
1145 *} |
1143 \<close> |
1146 |
1144 |
1147 ML %grayML{*val SOME ((un1, _), next1) = Seq.pull uni_seq; |
1145 ML %grayML\<open>val SOME ((un1, _), next1) = Seq.pull uni_seq; |
1148 val SOME ((un2, _), next2) = Seq.pull next1; |
1146 val SOME ((un2, _), next2) = Seq.pull next1; |
1149 val SOME ((un3, _), next3) = Seq.pull next2; |
1147 val SOME ((un3, _), next3) = Seq.pull next2; |
1150 val NONE = Seq.pull next3 *} |
1148 val NONE = Seq.pull next3\<close> |
1151 |
1149 |
1152 text {* |
1150 text \<open> |
1153 \footnote{\bf FIXME: what is the list of term pairs in the unifier: flex-flex pairs?} |
1151 \footnote{\bf FIXME: what is the list of term pairs in the unifier: flex-flex pairs?} |
1154 |
1152 |
1155 We can print them out as follows. |
1153 We can print them out as follows. |
1156 |
1154 |
1157 @{ML_response_fake [display, gray] |
1155 @{ML_response_fake [display, gray] |
1205 Here we only have a look at a simple case, namely the theorem |
1203 Here we only have a look at a simple case, namely the theorem |
1206 @{thm [source] spec}: |
1204 @{thm [source] spec}: |
1207 |
1205 |
1208 \begin{isabelle} |
1206 \begin{isabelle} |
1209 \isacommand{thm}~@{thm [source] spec}\\ |
1207 \isacommand{thm}~@{thm [source] spec}\\ |
1210 @{text "> "}~@{thm spec} |
1208 \<open>> \<close>~@{thm spec} |
1211 \end{isabelle} |
1209 \end{isabelle} |
1212 |
1210 |
1213 as an introduction rule. Applying it directly can lead to unexpected |
1211 as an introduction rule. Applying it directly can lead to unexpected |
1214 behaviour since the unification has more than one solution. One way round |
1212 behaviour since the unification has more than one solution. One way round |
1215 this problem is to instantiate the schematic variables @{text "?P"} and |
1213 this problem is to instantiate the schematic variables \<open>?P\<close> and |
1216 @{text "?x"}. Instantiation function for theorems is |
1214 \<open>?x\<close>. Instantiation function for theorems is |
1217 @{ML_ind instantiate_normalize in Drule} from the structure |
1215 @{ML_ind instantiate_normalize in Drule} from the structure |
1218 @{ML_struct Drule}. One problem, however, is |
1216 @{ML_struct Drule}. One problem, however, is |
1219 that this function expects the instantiations as lists of @{ML_type "((indexname * sort) * ctyp)"} |
1217 that this function expects the instantiations as lists of @{ML_type "((indexname * sort) * ctyp)"} |
1220 respective @{ML_type "(indexname * typ) * cterm"}: |
1218 respective @{ML_type "(indexname * typ) * cterm"}: |
1221 |
1219 |
1222 \begin{isabelle} |
1220 \begin{isabelle} |
1223 @{ML instantiate_normalize in Drule}@{text ":"} |
1221 @{ML instantiate_normalize in Drule}\<open>:\<close> |
1224 @{ML_type "((indexname * sort) * ctyp) list * ((indexname * typ) * cterm) list -> thm -> thm"} |
1222 @{ML_type "((indexname * sort) * ctyp) list * ((indexname * typ) * cterm) list -> thm -> thm"} |
1225 \end{isabelle} |
1223 \end{isabelle} |
1226 |
1224 |
1227 This means we have to transform the environment the higher-order matching |
1225 This means we have to transform the environment the higher-order matching |
1228 function returns into such an instantiation. For this we use the functions |
1226 function returns into such an instantiation. For this we use the functions |
1229 @{ML_ind term_env in Envir} and @{ML_ind type_env in Envir}, which extract |
1227 @{ML_ind term_env in Envir} and @{ML_ind type_env in Envir}, which extract |
1230 from an environment the corresponding variable mappings for schematic type |
1228 from an environment the corresponding variable mappings for schematic type |
1231 and term variables. These mappings can be turned into proper |
1229 and term variables. These mappings can be turned into proper |
1232 @{ML_type ctyp}-pairs with the function |
1230 @{ML_type ctyp}-pairs with the function |
1233 *} |
1231 \<close> |
1234 |
1232 |
1235 ML %grayML{*fun prep_trm ctxt (x, (T, t)) = |
1233 ML %grayML\<open>fun prep_trm ctxt (x, (T, t)) = |
1236 ((x, T), Thm.cterm_of ctxt t)*} |
1234 ((x, T), Thm.cterm_of ctxt t)\<close> |
1237 |
1235 |
1238 text {* |
1236 text \<open> |
1239 and into proper @{ML_type cterm}-pairs with |
1237 and into proper @{ML_type cterm}-pairs with |
1240 *} |
1238 \<close> |
1241 |
1239 |
1242 ML %grayML{*fun prep_ty ctxt (x, (S, ty)) = |
1240 ML %grayML\<open>fun prep_ty ctxt (x, (S, ty)) = |
1243 ((x, S), Thm.ctyp_of ctxt ty)*} |
1241 ((x, S), Thm.ctyp_of ctxt ty)\<close> |
1244 |
1242 |
1245 text {* |
1243 text \<open> |
1246 We can now calculate the instantiations from the matching function. |
1244 We can now calculate the instantiations from the matching function. |
1247 *} |
1245 \<close> |
1248 |
1246 |
1249 ML %linenosgray{*fun matcher_inst ctxt pat trm i = |
1247 ML %linenosgray\<open>fun matcher_inst ctxt pat trm i = |
1250 let |
1248 let |
1251 val univ = Unify.matchers (Context.Proof ctxt) [(pat, trm)] |
1249 val univ = Unify.matchers (Context.Proof ctxt) [(pat, trm)] |
1252 val env = nth (Seq.list_of univ) i |
1250 val env = nth (Seq.list_of univ) i |
1253 val tenv = Vartab.dest (Envir.term_env env) |
1251 val tenv = Vartab.dest (Envir.term_env env) |
1254 val tyenv = Vartab.dest (Envir.type_env env) |
1252 val tyenv = Vartab.dest (Envir.type_env env) |
1255 in |
1253 in |
1256 (map (prep_ty ctxt) tyenv, map (prep_trm ctxt) tenv) |
1254 (map (prep_ty ctxt) tyenv, map (prep_trm ctxt) tenv) |
1257 end*} |
1255 end\<close> |
1258 |
1256 |
1259 ML \<open>Context.get_generic_context\<close> |
1257 ML \<open>Context.get_generic_context\<close> |
1260 text {* |
1258 text \<open> |
1261 In Line 3 we obtain the higher-order matcher. We assume there is a finite |
1259 In Line 3 we obtain the higher-order matcher. We assume there is a finite |
1262 number of them and select the one we are interested in via the parameter |
1260 number of them and select the one we are interested in via the parameter |
1263 @{text i} in the next line. In Lines 5 and 6 we destruct the resulting |
1261 \<open>i\<close> in the next line. In Lines 5 and 6 we destruct the resulting |
1264 environments using the function @{ML_ind dest in Vartab}. Finally, we need |
1262 environments using the function @{ML_ind dest in Vartab}. Finally, we need |
1265 to map the functions @{ML prep_trm} and @{ML prep_ty} over the respective |
1263 to map the functions @{ML prep_trm} and @{ML prep_ty} over the respective |
1266 environments (Line 8). As a simple example we instantiate the |
1264 environments (Line 8). As a simple example we instantiate the |
1267 @{thm [source] spec} rule so that its conclusion is of the form |
1265 @{thm [source] spec} rule so that its conclusion is of the form |
1268 @{term "Q True"}. |
1266 @{term "Q True"}. |
1573 referenced on the user level. One way to store it in the theorem database is |
1571 referenced on the user level. One way to store it in the theorem database is |
1574 by using the function @{ML_ind note in Local_Theory} from the structure |
1572 by using the function @{ML_ind note in Local_Theory} from the structure |
1575 @{ML_struct Local_Theory} (the Isabelle command |
1573 @{ML_struct Local_Theory} (the Isabelle command |
1576 \isacommand{local\_setup} will be explained in more detail in |
1574 \isacommand{local\_setup} will be explained in more detail in |
1577 Section~\ref{sec:local}). |
1575 Section~\ref{sec:local}). |
1578 *} |
1576 \<close> |
1579 |
1577 |
1580 (*FIXME: add forward reference to Proof_Context.export *) |
1578 (*FIXME: add forward reference to Proof_Context.export *) |
1581 ML %linenosgray{*val my_thm_vars = |
1579 ML %linenosgray\<open>val my_thm_vars = |
1582 let |
1580 let |
1583 val ctxt0 = @{context} |
1581 val ctxt0 = @{context} |
1584 val (_, ctxt1) = Variable.add_fixes ["P", "Q", "t"] ctxt0 |
1582 val (_, ctxt1) = Variable.add_fixes ["P", "Q", "t"] ctxt0 |
1585 in |
1583 in |
1586 singleton (Proof_Context.export ctxt1 ctxt0) my_thm |
1584 singleton (Proof_Context.export ctxt1 ctxt0) my_thm |
1587 end*} |
1585 end\<close> |
1588 |
1586 |
1589 local_setup %gray {* |
1587 local_setup %gray \<open> |
1590 Local_Theory.note ((@{binding "my_thm"}, []), [my_thm_vars]) #> snd *} |
1588 Local_Theory.note ((@{binding "my_thm"}, []), [my_thm_vars]) #> snd\<close> |
1591 |
1589 |
1592 |
1590 |
1593 text {* |
1591 text \<open> |
1594 The third argument of @{ML note in Local_Theory} is the list of theorems we |
1592 The third argument of @{ML note in Local_Theory} is the list of theorems we |
1595 want to store under a name. We can store more than one under a single name. |
1593 want to store under a name. We can store more than one under a single name. |
1596 The first argument of @{ML note in Local_Theory} is the name under |
1594 The first argument of @{ML note in Local_Theory} is the name under |
1597 which we store the theorem or theorems. The second argument can contain a |
1595 which we store the theorem or theorems. The second argument can contain a |
1598 list of theorem attributes, which we will explain in detail in |
1596 list of theorem attributes, which we will explain in detail in |
1599 Section~\ref{sec:attributes}. Below we just use one such attribute, |
1597 Section~\ref{sec:attributes}. Below we just use one such attribute, |
1600 @{ML_ind simp_add in Simplifier}, for adding the theorem to the simpset: |
1598 @{ML_ind simp_add in Simplifier}, for adding the theorem to the simpset: |
1601 *} |
1599 \<close> |
1602 |
1600 |
1603 local_setup %gray {* |
1601 local_setup %gray \<open> |
1604 Local_Theory.note ((@{binding "my_thm_simp"}, |
1602 Local_Theory.note ((@{binding "my_thm_simp"}, |
1605 [Attrib.internal (K Simplifier.simp_add)]), [my_thm_vars]) #> snd *} |
1603 [Attrib.internal (K Simplifier.simp_add)]), [my_thm_vars]) #> snd\<close> |
1606 |
1604 |
1607 text {* |
1605 text \<open> |
1608 Note that we have to use another name under which the theorem is stored, |
1606 Note that we have to use another name under which the theorem is stored, |
1609 since Isabelle does not allow us to call @{ML_ind note in Local_Theory} twice |
1607 since Isabelle does not allow us to call @{ML_ind note in Local_Theory} twice |
1610 with the same name. The attribute needs to be wrapped inside the function @{ML_ind |
1608 with the same name. The attribute needs to be wrapped inside the function @{ML_ind |
1611 internal in Attrib} from the structure @{ML_struct Attrib}. If we use the function |
1609 internal in Attrib} from the structure @{ML_struct Attrib}. If we use the function |
1612 @{ML get_thm_names_from_ss} from |
1610 @{ML get_thm_names_from_ss} from |
1626 [source] my_thm_simp} is that they can now also be referenced with the |
1624 [source] my_thm_simp} is that they can now also be referenced with the |
1627 \isacommand{thm}-command on the user-level of Isabelle |
1625 \isacommand{thm}-command on the user-level of Isabelle |
1628 |
1626 |
1629 |
1627 |
1630 \begin{isabelle} |
1628 \begin{isabelle} |
1631 \isacommand{thm}~@{text "my_thm my_thm_simp"}\isanewline |
1629 \isacommand{thm}~\<open>my_thm my_thm_simp\<close>\isanewline |
1632 @{text ">"}~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}\isanewline |
1630 \<open>>\<close>~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}\isanewline |
1633 @{text ">"}~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"} |
1631 \<open>>\<close>~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"} |
1634 \end{isabelle} |
1632 \end{isabelle} |
1635 |
1633 |
1636 or with the @{text "@{thm \<dots>}"}-antiquotation on the ML-level. Otherwise the |
1634 or with the \<open>@{thm \<dots>}\<close>-antiquotation on the ML-level. Otherwise the |
1637 user has no access to these theorems. |
1635 user has no access to these theorems. |
1638 |
1636 |
1639 Recall that Isabelle does not let you call @{ML note in Local_Theory} twice |
1637 Recall that Isabelle does not let you call @{ML note in Local_Theory} twice |
1640 with the same theorem name. In effect, once a theorem is stored under a name, |
1638 with the same theorem name. In effect, once a theorem is stored under a name, |
1641 this association is fixed. While this is a ``safety-net'' to make sure a |
1639 this association is fixed. While this is a ``safety-net'' to make sure a |
1642 theorem name refers to a particular theorem or collection of theorems, it is |
1640 theorem name refers to a particular theorem or collection of theorems, it is |
1643 also a bit too restrictive in cases where a theorem name should refer to a |
1641 also a bit too restrictive in cases where a theorem name should refer to a |
1644 dynamically expanding list of theorems (like a simpset). Therefore Isabelle |
1642 dynamically expanding list of theorems (like a simpset). Therefore Isabelle |
1645 also implements a mechanism where a theorem name can refer to a custom theorem |
1643 also implements a mechanism where a theorem name can refer to a custom theorem |
1646 list. For this you can use the function @{ML_ind add_thms_dynamic in Global_Theory}. |
1644 list. For this you can use the function @{ML_ind add_thms_dynamic in Global_Theory}. |
1647 To see how it works let us assume we defined our own theorem list @{text MyThmList}. |
1645 To see how it works let us assume we defined our own theorem list \<open>MyThmList\<close>. |
1648 *} |
1646 \<close> |
1649 |
1647 |
1650 ML %grayML{*structure MyThmList = Generic_Data |
1648 ML %grayML\<open>structure MyThmList = Generic_Data |
1651 (type T = thm list |
1649 (type T = thm list |
1652 val empty = [] |
1650 val empty = [] |
1653 val extend = I |
1651 val extend = I |
1654 val merge = merge Thm.eq_thm_prop) |
1652 val merge = merge Thm.eq_thm_prop) |
1655 |
1653 |
1656 fun update thm = Context.theory_map (MyThmList.map (Thm.add_thm thm))*} |
1654 fun update thm = Context.theory_map (MyThmList.map (Thm.add_thm thm))\<close> |
1657 |
1655 |
1658 text {* |
1656 text \<open> |
1659 The function @{ML update} allows us to update the theorem list, for example |
1657 The function @{ML update} allows us to update the theorem list, for example |
1660 by adding the theorem @{thm [source] TrueI}. |
1658 by adding the theorem @{thm [source] TrueI}. |
1661 *} |
1659 \<close> |
1662 |
1660 |
1663 setup %gray {* update @{thm TrueI} *} |
1661 setup %gray \<open>update @{thm TrueI}\<close> |
1664 |
1662 |
1665 text {* |
1663 text \<open> |
1666 We can now install the theorem list so that it is visible to the user and |
1664 We can now install the theorem list so that it is visible to the user and |
1667 can be refered to by a theorem name. For this need to call |
1665 can be refered to by a theorem name. For this need to call |
1668 @{ML_ind add_thms_dynamic in Global_Theory} |
1666 @{ML_ind add_thms_dynamic in Global_Theory} |
1669 *} |
1667 \<close> |
1670 |
1668 |
1671 setup %gray {* |
1669 setup %gray \<open> |
1672 Global_Theory.add_thms_dynamic (@{binding "mythmlist"}, MyThmList.get) |
1670 Global_Theory.add_thms_dynamic (@{binding "mythmlist"}, MyThmList.get) |
1673 *} |
1671 \<close> |
1674 |
1672 |
1675 text {* |
1673 text \<open> |
1676 with a name and a function that accesses the theorem list. Now if the |
1674 with a name and a function that accesses the theorem list. Now if the |
1677 user issues the command |
1675 user issues the command |
1678 |
1676 |
1679 \begin{isabelle} |
1677 \begin{isabelle} |
1680 \isacommand{thm}~@{text "mythmlist"}\\ |
1678 \isacommand{thm}~\<open>mythmlist\<close>\\ |
1681 @{text "> True"} |
1679 \<open>> True\<close> |
1682 \end{isabelle} |
1680 \end{isabelle} |
1683 |
1681 |
1684 the current content of the theorem list is displayed. If more theorems are stored in |
1682 the current content of the theorem list is displayed. If more theorems are stored in |
1685 the list, say |
1683 the list, say |
1686 *} |
1684 \<close> |
1687 |
1685 |
1688 setup %gray {* update @{thm FalseE} *} |
1686 setup %gray \<open>update @{thm FalseE}\<close> |
1689 |
1687 |
1690 text {* |
1688 text \<open> |
1691 then the same command produces |
1689 then the same command produces |
1692 |
1690 |
1693 \begin{isabelle} |
1691 \begin{isabelle} |
1694 \isacommand{thm}~@{text "mythmlist"}\\ |
1692 \isacommand{thm}~\<open>mythmlist\<close>\\ |
1695 @{text "> False \<Longrightarrow> ?P"}\\ |
1693 \<open>> False \<Longrightarrow> ?P\<close>\\ |
1696 @{text "> True"} |
1694 \<open>> True\<close> |
1697 \end{isabelle} |
1695 \end{isabelle} |
1698 |
1696 |
1699 Note that if we add the theorem @{thm [source] FalseE} again to the list |
1697 Note that if we add the theorem @{thm [source] FalseE} again to the list |
1700 *} |
1698 \<close> |
1701 |
1699 |
1702 setup %gray {* update @{thm FalseE} *} |
1700 setup %gray \<open>update @{thm FalseE}\<close> |
1703 |
1701 |
1704 text {* |
1702 text \<open> |
1705 we still obtain the same list. The reason is that we used the function @{ML_ind |
1703 we still obtain the same list. The reason is that we used the function @{ML_ind |
1706 add_thm in Thm} in our update function. This is a dedicated function which |
1704 add_thm in Thm} in our update function. This is a dedicated function which |
1707 tests whether the theorem is already in the list. This test is done |
1705 tests whether the theorem is already in the list. This test is done |
1708 according to alpha-equivalence of the proposition of the theorem. The |
1706 according to alpha-equivalence of the proposition of the theorem. The |
1709 corresponding testing function is @{ML_ind eq_thm_prop in Thm}. |
1707 corresponding testing function is @{ML_ind eq_thm_prop in Thm}. |
1710 Suppose you proved the following three theorems. |
1708 Suppose you proved the following three theorems. |
1711 *} |
1709 \<close> |
1712 |
1710 |
1713 lemma |
1711 lemma |
1714 shows thm1: "\<forall>x. P x" |
1712 shows thm1: "\<forall>x. P x" |
1715 and thm2: "\<forall>y. P y" |
1713 and thm2: "\<forall>y. P y" |
1716 and thm3: "\<forall>y. Q y" sorry |
1714 and thm3: "\<forall>y. Q y" sorry |
1717 |
1715 |
1718 text {* |
1716 text \<open> |
1719 Testing them for alpha equality produces: |
1717 Testing them for alpha equality produces: |
1720 |
1718 |
1721 @{ML_response [display,gray] |
1719 @{ML_response [display,gray] |
1722 "(Thm.eq_thm_prop (@{thm thm1}, @{thm thm2}), |
1720 "(Thm.eq_thm_prop (@{thm thm1}, @{thm thm2}), |
1723 Thm.eq_thm_prop (@{thm thm2}, @{thm thm3}))" |
1721 Thm.eq_thm_prop (@{thm thm2}, @{thm thm3}))" |
1857 end" |
1855 end" |
1858 "?P \<Longrightarrow> ?P"} |
1856 "?P \<Longrightarrow> ?P"} |
1859 |
1857 |
1860 This function takes first a context and second a list of strings. This list |
1858 This function takes first a context and second a list of strings. This list |
1861 specifies which variables should be turned into schematic variables once the term |
1859 specifies which variables should be turned into schematic variables once the term |
1862 is proved (in this case only @{text "\"P\""}). The fourth argument is the term to be |
1860 is proved (in this case only \<open>"P"\<close>). The fourth argument is the term to be |
1863 proved. The fifth is a corresponding proof given in form of a tactic (we explain |
1861 proved. The fifth is a corresponding proof given in form of a tactic (we explain |
1864 tactics in Chapter~\ref{chp:tactical}). In the code above, the tactic proves the |
1862 tactics in Chapter~\ref{chp:tactical}). In the code above, the tactic proves the |
1865 theorem by assumption. |
1863 theorem by assumption. |
1866 |
1864 |
1867 There is also the possibility of proving multiple goals at the same time |
1865 There is also the possibility of proving multiple goals at the same time |
1868 using the function @{ML_ind prove_common in Goal}. For this let us define the |
1866 using the function @{ML_ind prove_common in Goal}. For this let us define the |
1869 following three helper functions. |
1867 following three helper functions. |
1870 *} |
1868 \<close> |
1871 |
1869 |
1872 ML %grayML{*fun rep_goals i = replicate i @{prop "f x = f x"} |
1870 ML %grayML\<open>fun rep_goals i = replicate i @{prop "f x = f x"} |
1873 fun rep_tacs i = replicate i (resolve_tac @{context} [@{thm refl}]) |
1871 fun rep_tacs i = replicate i (resolve_tac @{context} [@{thm refl}]) |
1874 |
1872 |
1875 fun multi_test ctxt i = |
1873 fun multi_test ctxt i = |
1876 Goal.prove_common ctxt NONE ["f", "x"] [] (rep_goals i) |
1874 Goal.prove_common ctxt NONE ["f", "x"] [] (rep_goals i) |
1877 (K ((Goal.conjunction_tac THEN' RANGE (rep_tacs i)) 1))*} |
1875 (K ((Goal.conjunction_tac THEN' RANGE (rep_tacs i)) 1))\<close> |
1878 |
1876 |
1879 text {* |
1877 text \<open> |
1880 With them we can now produce three theorem instances of the |
1878 With them we can now produce three theorem instances of the |
1881 proposition. |
1879 proposition. |
1882 |
1880 |
1883 @{ML_response_fake [display, gray] |
1881 @{ML_response_fake [display, gray] |
1884 "multi_test @{context} 3" |
1882 "multi_test @{context} 3" |
1885 "[\"?f ?x = ?f ?x\", \"?f ?x = ?f ?x\", \"?f ?x = ?f ?x\"]"} |
1883 "[\"?f ?x = ?f ?x\", \"?f ?x = ?f ?x\", \"?f ?x = ?f ?x\"]"} |
1886 |
1884 |
1887 However you should be careful with @{ML prove_common in Goal} and very |
1885 However you should be careful with @{ML prove_common in Goal} and very |
1888 large goals. If you increase the counter in the code above to @{text 3000}, |
1886 large goals. If you increase the counter in the code above to \<open>3000\<close>, |
1889 you will notice that takes approximately ten(!) times longer than |
1887 you will notice that takes approximately ten(!) times longer than |
1890 using @{ML map} and @{ML prove in Goal}. |
1888 using @{ML map} and @{ML prove in Goal}. |
1891 *} |
1889 \<close> |
1892 |
1890 |
1893 ML %grayML{*let |
1891 ML %grayML\<open>let |
1894 fun test_prove ctxt thm = |
1892 fun test_prove ctxt thm = |
1895 Goal.prove ctxt ["P", "x"] [] thm (K (resolve_tac @{context} [@{thm refl}] 1)) |
1893 Goal.prove ctxt ["P", "x"] [] thm (K (resolve_tac @{context} [@{thm refl}] 1)) |
1896 in |
1894 in |
1897 map (test_prove @{context}) (rep_goals 3000) |
1895 map (test_prove @{context}) (rep_goals 3000) |
1898 end*} |
1896 end\<close> |
1899 |
1897 |
1900 text {* |
1898 text \<open> |
1901 While the LCF-approach of going through interfaces ensures soundness in Isabelle, there |
1899 While the LCF-approach of going through interfaces ensures soundness in Isabelle, there |
1902 is the function @{ML_ind make_thm in Skip_Proof} in the structure |
1900 is the function @{ML_ind make_thm in Skip_Proof} in the structure |
1903 @{ML_struct Skip_Proof} that allows us to turn any proposition into a theorem. |
1901 @{ML_struct Skip_Proof} that allows us to turn any proposition into a theorem. |
1904 Potentially making the system unsound. This is sometimes useful for developing |
1902 Potentially making the system unsound. This is sometimes useful for developing |
1905 purposes, or when explicit proof construction should be omitted due to performace |
1903 purposes, or when explicit proof construction should be omitted due to performace |
1934 |
1932 |
1935 consisting of a name and a kind. When we store lemmas in the theorem database, |
1933 consisting of a name and a kind. When we store lemmas in the theorem database, |
1936 we might want to explicitly extend this data by attaching case names to the |
1934 we might want to explicitly extend this data by attaching case names to the |
1937 two premises of the lemma. This can be done with the function @{ML_ind name in Rule_Cases} |
1935 two premises of the lemma. This can be done with the function @{ML_ind name in Rule_Cases} |
1938 from the structure @{ML_struct Rule_Cases}. |
1936 from the structure @{ML_struct Rule_Cases}. |
1939 *} |
1937 \<close> |
1940 |
1938 |
1941 local_setup %gray {* |
1939 local_setup %gray \<open> |
1942 Local_Theory.note ((@{binding "foo_data'"}, []), |
1940 Local_Theory.note ((@{binding "foo_data'"}, []), |
1943 [(Rule_Cases.name ["foo_case_one", "foo_case_two"] |
1941 [(Rule_Cases.name ["foo_case_one", "foo_case_two"] |
1944 @{thm foo_data})]) #> snd *} |
1942 @{thm foo_data})]) #> snd\<close> |
1945 |
1943 |
1946 text {* |
1944 text \<open> |
1947 The data of the theorem @{thm [source] foo_data'} is then as follows: |
1945 The data of the theorem @{thm [source] foo_data'} is then as follows: |
1948 |
1946 |
1949 @{ML_response_fake [display,gray] |
1947 @{ML_response_fake [display,gray] |
1950 "Thm.get_tags @{thm foo_data'}" |
1948 "Thm.get_tags @{thm foo_data'}" |
1951 "[(\"name\", \"General.foo_data'\"), (\"kind\", \"lemma\"), |
1949 "[(\"name\", \"General.foo_data'\"), (\"kind\", \"lemma\"), |
1952 (\"case_names\", \"foo_case_one;foo_case_two\")]"} |
1950 (\"case_names\", \"foo_case_one;foo_case_two\")]"} |
1953 |
1951 |
1954 You can observe the case names of this lemma on the user level when using |
1952 You can observe the case names of this lemma on the user level when using |
1955 the proof methods @{text cases} and @{text induct}. In the proof below |
1953 the proof methods \<open>cases\<close> and \<open>induct\<close>. In the proof below |
1956 *} |
1954 \<close> |
1957 |
1955 |
1958 lemma |
1956 lemma |
1959 shows "Q \<Longrightarrow> Q \<Longrightarrow> Q" |
1957 shows "Q \<Longrightarrow> Q \<Longrightarrow> Q" |
1960 proof (cases rule: foo_data') |
1958 proof (cases rule: foo_data') |
1961 |
1959 |
1962 (*<*)oops(*>*) |
1960 (*<*)oops(*>*) |
1963 text_raw{* |
1961 text_raw\<open> |
1964 \begin{tabular}{@ {}l} |
1962 \begin{tabular}{@ {}l} |
1965 \isacommand{print\_cases}\\ |
1963 \isacommand{print\_cases}\\ |
1966 @{text "> cases:"}\\ |
1964 \<open>> cases:\<close>\\ |
1967 @{text "> foo_case_one:"}\\ |
1965 \<open>> foo_case_one:\<close>\\ |
1968 @{text "> let \"?case\" = \"?P\""}\\ |
1966 \<open>> let "?case" = "?P"\<close>\\ |
1969 @{text "> foo_case_two:"}\\ |
1967 \<open>> foo_case_two:\<close>\\ |
1970 @{text "> let \"?case\" = \"?P\""} |
1968 \<open>> let "?case" = "?P"\<close> |
1971 \end{tabular}*} |
1969 \end{tabular}\<close> |
1972 |
1970 |
1973 text {* |
1971 text \<open> |
1974 we can proceed by analysing the cases @{text "foo_case_one"} and |
1972 we can proceed by analysing the cases \<open>foo_case_one\<close> and |
1975 @{text "foo_case_two"}. While if the theorem has no names, then |
1973 \<open>foo_case_two\<close>. While if the theorem has no names, then |
1976 the cases have standard names @{text 1}, @{text 2} and so |
1974 the cases have standard names \<open>1\<close>, \<open>2\<close> and so |
1977 on. This can be seen in the proof below. |
1975 on. This can be seen in the proof below. |
1978 *} |
1976 \<close> |
1979 |
1977 |
1980 lemma |
1978 lemma |
1981 shows "Q \<Longrightarrow> Q \<Longrightarrow> Q" |
1979 shows "Q \<Longrightarrow> Q \<Longrightarrow> Q" |
1982 proof (cases rule: foo_data) |
1980 proof (cases rule: foo_data) |
1983 |
1981 |
1984 (*<*)oops(*>*) |
1982 (*<*)oops(*>*) |
1985 text_raw{* |
1983 text_raw\<open> |
1986 \begin{tabular}{@ {}l} |
1984 \begin{tabular}{@ {}l} |
1987 \isacommand{print\_cases}\\ |
1985 \isacommand{print\_cases}\\ |
1988 @{text "> cases:"}\\ |
1986 \<open>> cases:\<close>\\ |
1989 @{text "> 1:"}\\ |
1987 \<open>> 1:\<close>\\ |
1990 @{text "> let \"?case\" = \"?P\""}\\ |
1988 \<open>> let "?case" = "?P"\<close>\\ |
1991 @{text "> 2:"}\\ |
1989 \<open>> 2:\<close>\\ |
1992 @{text "> let \"?case\" = \"?P\""} |
1990 \<open>> let "?case" = "?P"\<close> |
1993 \end{tabular}*} |
1991 \end{tabular}\<close> |
1994 |
1992 |
1995 |
1993 |
1996 text {* |
1994 text \<open> |
1997 Sometimes one wants to know the theorems that are involved in |
1995 Sometimes one wants to know the theorems that are involved in |
1998 proving a theorem, especially when the proof is by @{text |
1996 proving a theorem, especially when the proof is by \<open>auto\<close>. These theorems can be obtained by introspecting the proved theorem. |
1999 auto}. These theorems can be obtained by introspecting the proved theorem. |
|
2000 To introspect a theorem, let us define the following three functions |
1997 To introspect a theorem, let us define the following three functions |
2001 that analyse the @{ML_type_ind proof_body} data-structure from the |
1998 that analyse the @{ML_type_ind proof_body} data-structure from the |
2002 structure @{ML_struct Proofterm}. |
1999 structure @{ML_struct Proofterm}. |
2003 *} |
2000 \<close> |
2004 |
2001 |
2005 ML %grayML{*fun pthms_of (PBody {thms, ...}) = map #2 thms |
2002 ML %grayML\<open>fun pthms_of (PBody {thms, ...}) = map #2 thms |
2006 val get_names = (map Proofterm.thm_node_name) o pthms_of |
2003 val get_names = (map Proofterm.thm_node_name) o pthms_of |
2007 val get_pbodies = map (Future.join o Proofterm.thm_node_body) o pthms_of *} |
2004 val get_pbodies = map (Future.join o Proofterm.thm_node_body) o pthms_of\<close> |
2008 |
2005 |
2009 text {* |
2006 text \<open> |
2010 To see what their purpose is, consider the following three short proofs. |
2007 To see what their purpose is, consider the following three short proofs. |
2011 *} |
2008 \<close> |
2012 |
2009 |
2013 lemma my_conjIa: |
2010 lemma my_conjIa: |
2014 shows "A \<and> B \<Longrightarrow> A \<and> B" |
2011 shows "A \<and> B \<Longrightarrow> A \<and> B" |
2015 apply(rule conjI) |
2012 apply(rule conjI) |
2016 apply(drule conjunct1) |
2013 apply(drule conjunct1) |
2124 sometimes the verbatim quoting is not what is wanted or what can be shown to |
2121 sometimes the verbatim quoting is not what is wanted or what can be shown to |
2125 readers. For such situations Isabelle allows the installation of \emph{\index*{theorem |
2122 readers. For such situations Isabelle allows the installation of \emph{\index*{theorem |
2126 styles}}. These are, roughly speaking, functions from terms to terms. The input |
2123 styles}}. These are, roughly speaking, functions from terms to terms. The input |
2127 term stands for the theorem to be presented; the output can be constructed to |
2124 term stands for the theorem to be presented; the output can be constructed to |
2128 ones wishes. Let us, for example, assume we want to quote theorems without |
2125 ones wishes. Let us, for example, assume we want to quote theorems without |
2129 leading @{text \<forall>}-quantifiers. For this we can implement the following function |
2126 leading \<open>\<forall>\<close>-quantifiers. For this we can implement the following function |
2130 that strips off @{text "\<forall>"}s. |
2127 that strips off \<open>\<forall>\<close>s. |
2131 *} |
2128 \<close> |
2132 |
2129 |
2133 ML %linenosgray{*fun strip_allq (Const (@{const_name "All"}, _) $ Abs body) = |
2130 ML %linenosgray\<open>fun strip_allq (Const (@{const_name "All"}, _) $ Abs body) = |
2134 Term.dest_abs body |> snd |> strip_allq |
2131 Term.dest_abs body |> snd |> strip_allq |
2135 | strip_allq (Const (@{const_name "Trueprop"}, _) $ t) = |
2132 | strip_allq (Const (@{const_name "Trueprop"}, _) $ t) = |
2136 strip_allq t |
2133 strip_allq t |
2137 | strip_allq t = t*} |
2134 | strip_allq t = t\<close> |
2138 |
2135 |
2139 text {* |
2136 text \<open> |
2140 We use in Line 2 the function @{ML_ind dest_abs in Term} for deconstructing abstractions, |
2137 We use in Line 2 the function @{ML_ind dest_abs in Term} for deconstructing abstractions, |
2141 since this function deals correctly with potential name clashes. This function produces |
2138 since this function deals correctly with potential name clashes. This function produces |
2142 a pair consisting of the variable and the body of the abstraction. We are only interested |
2139 a pair consisting of the variable and the body of the abstraction. We are only interested |
2143 in the body, which we feed into the recursive call. In Line 3 and 4, we also |
2140 in the body, which we feed into the recursive call. In Line 3 and 4, we also |
2144 have to explicitly strip of the outermost @{term Trueprop}-coercion. Now we can |
2141 have to explicitly strip of the outermost @{term Trueprop}-coercion. Now we can |
2145 install this function as the theorem style named @{text "my_strip_allq"}. |
2142 install this function as the theorem style named \<open>my_strip_allq\<close>. |
2146 *} |
2143 \<close> |
2147 |
2144 |
2148 setup %gray{* |
2145 setup %gray\<open> |
2149 Term_Style.setup @{binding "my_strip_allq"} (Scan.succeed (K strip_allq)) |
2146 Term_Style.setup @{binding "my_strip_allq"} (Scan.succeed (K strip_allq)) |
2150 *} |
2147 \<close> |
2151 |
2148 |
2152 text {* |
2149 text \<open> |
2153 We can test this theorem style with the following theorem |
2150 We can test this theorem style with the following theorem |
2154 *} |
2151 \<close> |
2155 |
2152 |
2156 theorem style_test: |
2153 theorem style_test: |
2157 shows "\<forall>x y z. (x, x) = (y, z)" sorry |
2154 shows "\<forall>x y z. (x, x) = (y, z)" sorry |
2158 |
2155 |
2159 text {* |
2156 text \<open> |
2160 Now printing out in a document the theorem @{thm [source] style_test} normally |
2157 Now printing out in a document the theorem @{thm [source] style_test} normally |
2161 using @{text "@{thm \<dots>}"} produces |
2158 using \<open>@{thm \<dots>}\<close> produces |
2162 |
2159 |
2163 \begin{isabelle} |
2160 \begin{isabelle} |
2164 \begin{graybox} |
2161 \begin{graybox} |
2165 @{text "@{thm style_test}"}\\ |
2162 \<open>@{thm style_test}\<close>\\ |
2166 @{text ">"}~@{thm style_test} |
2163 \<open>>\<close>~@{thm style_test} |
2167 \end{graybox} |
2164 \end{graybox} |
2168 \end{isabelle} |
2165 \end{isabelle} |
2169 |
2166 |
2170 as expected. But with the theorem style @{text "@{thm (my_strip_allq) \<dots>}"} |
2167 as expected. But with the theorem style \<open>@{thm (my_strip_allq) \<dots>}\<close> |
2171 we obtain |
2168 we obtain |
2172 |
2169 |
2173 \begin{isabelle} |
2170 \begin{isabelle} |
2174 \begin{graybox} |
2171 \begin{graybox} |
2175 @{text "@{thm (my_strip_allq) style_test}"}\\ |
2172 \<open>@{thm (my_strip_allq) style_test}\<close>\\ |
2176 @{text ">"}~@{thm (my_strip_allq) style_test} |
2173 \<open>>\<close>~@{thm (my_strip_allq) style_test} |
2177 \end{graybox} |
2174 \end{graybox} |
2178 \end{isabelle} |
2175 \end{isabelle} |
2179 |
2176 |
2180 without the leading quantifiers. We can improve this theorem style by explicitly |
2177 without the leading quantifiers. We can improve this theorem style by explicitly |
2181 giving a list of strings that should be used for the replacement of the |
2178 giving a list of strings that should be used for the replacement of the |
2182 variables. For this we implement the function which takes a list of strings |
2179 variables. For this we implement the function which takes a list of strings |
2183 and uses them as name in the outermost abstractions. |
2180 and uses them as name in the outermost abstractions. |
2184 *} |
2181 \<close> |
2185 |
2182 |
2186 ML %grayML{*fun rename_allq [] t = t |
2183 ML %grayML\<open>fun rename_allq [] t = t |
2187 | rename_allq (x::xs) (Const (@{const_name "All"}, U) $ Abs (_, T, t)) = |
2184 | rename_allq (x::xs) (Const (@{const_name "All"}, U) $ Abs (_, T, t)) = |
2188 Const (@{const_name "All"}, U) $ Abs (x, T, rename_allq xs t) |
2185 Const (@{const_name "All"}, U) $ Abs (x, T, rename_allq xs t) |
2189 | rename_allq xs (Const (@{const_name "Trueprop"}, U) $ t) = |
2186 | rename_allq xs (Const (@{const_name "Trueprop"}, U) $ t) = |
2190 rename_allq xs t |
2187 rename_allq xs t |
2191 | rename_allq _ t = t*} |
2188 | rename_allq _ t = t\<close> |
2192 |
2189 |
2193 text {* |
2190 text \<open> |
2194 We can now install a the modified theorem style as follows |
2191 We can now install a the modified theorem style as follows |
2195 *} |
2192 \<close> |
2196 |
2193 |
2197 setup %gray {* let |
2194 setup %gray \<open>let |
2198 val parser = Scan.repeat Args.name |
2195 val parser = Scan.repeat Args.name |
2199 fun action xs = K (rename_allq xs #> strip_allq) |
2196 fun action xs = K (rename_allq xs #> strip_allq) |
2200 in |
2197 in |
2201 Term_Style.setup @{binding "my_strip_allq2"} (parser >> action) |
2198 Term_Style.setup @{binding "my_strip_allq2"} (parser >> action) |
2202 end *} |
2199 end\<close> |
2203 |
2200 |
2204 text {* |
2201 text \<open> |
2205 The parser reads a list of names. In the function @{text action} we first |
2202 The parser reads a list of names. In the function \<open>action\<close> we first |
2206 call @{ML rename_allq} with the parsed list, then we call @{ML strip_allq} |
2203 call @{ML rename_allq} with the parsed list, then we call @{ML strip_allq} |
2207 on the resulting term. We can now suggest, for example, two variables for |
2204 on the resulting term. We can now suggest, for example, two variables for |
2208 stripping off the first two @{text \<forall>}-quantifiers. |
2205 stripping off the first two \<open>\<forall>\<close>-quantifiers. |
2209 |
2206 |
2210 \begin{isabelle} |
2207 \begin{isabelle} |
2211 \begin{graybox} |
2208 \begin{graybox} |
2212 @{text "@{thm (my_strip_allq2 x' x'') style_test}"}\\ |
2209 \<open>@{thm (my_strip_allq2 x' x'') style_test}\<close>\\ |
2213 @{text ">"}~@{thm (my_strip_allq2 x' x'') style_test} |
2210 \<open>>\<close>~@{thm (my_strip_allq2 x' x'') style_test} |
2214 \end{graybox} |
2211 \end{graybox} |
2215 \end{isabelle} |
2212 \end{isabelle} |
2216 |
2213 |
2217 Such styles allow one to print out theorems in documents formatted to |
2214 Such styles allow one to print out theorems in documents formatted to |
2218 ones heart content. The styles can also be used in the document |
2215 ones heart content. The styles can also be used in the document |
2219 antiquotations @{text "@{prop ...}"}, @{text "@{term_type ...}"} |
2216 antiquotations \<open>@{prop ...}\<close>, \<open>@{term_type ...}\<close> |
2220 and @{text "@{typeof ...}"}. |
2217 and \<open>@{typeof ...}\<close>. |
2221 |
2218 |
2222 Next we explain theorem attributes, which is another |
2219 Next we explain theorem attributes, which is another |
2223 mechanism for dealing with theorems. |
2220 mechanism for dealing with theorems. |
2224 |
2221 |
2225 \begin{readmore} |
2222 \begin{readmore} |
2226 Theorem styles are implemented in @{ML_file "Pure/Thy/term_style.ML"}. |
2223 Theorem styles are implemented in @{ML_file "Pure/Thy/term_style.ML"}. |
2227 \end{readmore} |
2224 \end{readmore} |
2228 *} |
2225 \<close> |
2229 |
2226 |
2230 section {* Theorem Attributes\label{sec:attributes} *} |
2227 section \<open>Theorem Attributes\label{sec:attributes}\<close> |
2231 |
2228 |
2232 text {* |
2229 text \<open> |
2233 Theorem attributes are @{text "[symmetric]"}, @{text "[THEN \<dots>]"}, @{text |
2230 Theorem attributes are \<open>[symmetric]\<close>, \<open>[THEN \<dots>]\<close>, \<open>[simp]\<close> and so on. Such attributes are \emph{neither} tags \emph{nor} flags |
2234 "[simp]"} and so on. Such attributes are \emph{neither} tags \emph{nor} flags |
|
2235 annotated to theorems, but functions that do further processing of |
2231 annotated to theorems, but functions that do further processing of |
2236 theorems. In particular, it is not possible to find out |
2232 theorems. In particular, it is not possible to find out |
2237 what are all theorems that have a given attribute in common, unless of course |
2233 what are all theorems that have a given attribute in common, unless of course |
2238 the function behind the attribute stores the theorems in a retrievable |
2234 the function behind the attribute stores the theorems in a retrievable |
2239 data structure. |
2235 data structure. |
2241 If you want to print out all currently known attributes a theorem can have, |
2237 If you want to print out all currently known attributes a theorem can have, |
2242 you can use the Isabelle command |
2238 you can use the Isabelle command |
2243 |
2239 |
2244 \begin{isabelle} |
2240 \begin{isabelle} |
2245 \isacommand{print\_attributes}\\ |
2241 \isacommand{print\_attributes}\\ |
2246 @{text "> COMP: direct composition with rules (no lifting)"}\\ |
2242 \<open>> COMP: direct composition with rules (no lifting)\<close>\\ |
2247 @{text "> HOL.dest: declaration of Classical destruction rule"}\\ |
2243 \<open>> HOL.dest: declaration of Classical destruction rule\<close>\\ |
2248 @{text "> HOL.elim: declaration of Classical elimination rule"}\\ |
2244 \<open>> HOL.elim: declaration of Classical elimination rule\<close>\\ |
2249 @{text "> \<dots>"} |
2245 \<open>> \<dots>\<close> |
2250 \end{isabelle} |
2246 \end{isabelle} |
2251 |
2247 |
2252 The theorem attributes fall roughly into two categories: the first category manipulates |
2248 The theorem attributes fall roughly into two categories: the first category manipulates |
2253 theorems (for example @{text "[symmetric]"} and @{text "[THEN \<dots>]"}), and the second |
2249 theorems (for example \<open>[symmetric]\<close> and \<open>[THEN \<dots>]\<close>), and the second |
2254 stores theorems somewhere as data (for example @{text "[simp]"}, which adds |
2250 stores theorems somewhere as data (for example \<open>[simp]\<close>, which adds |
2255 theorems to the current simpset). |
2251 theorems to the current simpset). |
2256 |
2252 |
2257 To explain how to write your own attribute, let us start with an extremely simple |
2253 To explain how to write your own attribute, let us start with an extremely simple |
2258 version of the attribute @{text "[symmetric]"}. The purpose of this attribute is |
2254 version of the attribute \<open>[symmetric]\<close>. The purpose of this attribute is |
2259 to produce the ``symmetric'' version of an equation. The main function behind |
2255 to produce the ``symmetric'' version of an equation. The main function behind |
2260 this attribute is |
2256 this attribute is |
2261 *} |
2257 \<close> |
2262 |
2258 |
2263 ML %grayML{*val my_symmetric = Thm.rule_attribute [] (fn _ => fn thm => thm RS @{thm sym})*} |
2259 ML %grayML\<open>val my_symmetric = Thm.rule_attribute [] (fn _ => fn thm => thm RS @{thm sym})\<close> |
2264 |
2260 |
2265 text {* |
2261 text \<open> |
2266 where the function @{ML_ind rule_attribute in Thm} expects a function taking a |
2262 where the function @{ML_ind rule_attribute in Thm} expects a function taking a |
2267 context (which we ignore in the code above) and a theorem (@{text thm}), and |
2263 context (which we ignore in the code above) and a theorem (\<open>thm\<close>), and |
2268 returns another theorem (namely @{text thm} resolved with the theorem |
2264 returns another theorem (namely \<open>thm\<close> resolved with the theorem |
2269 @{thm [source] sym}: @{thm sym[no_vars]}; the function @{ML_ind RS in Drule} |
2265 @{thm [source] sym}: @{thm sym[no_vars]}; the function @{ML_ind RS in Drule} |
2270 is explained in Section~\ref{sec:simpletacs}). The function |
2266 is explained in Section~\ref{sec:simpletacs}). The function |
2271 @{ML rule_attribute in Thm} then returns an attribute. |
2267 @{ML rule_attribute in Thm} then returns an attribute. |
2272 |
2268 |
2273 Before we can use the attribute, we need to set it up. This can be done |
2269 Before we can use the attribute, we need to set it up. This can be done |
2274 using the Isabelle command \isacommand{attribute\_setup} as follows: |
2270 using the Isabelle command \isacommand{attribute\_setup} as follows: |
2275 *} |
2271 \<close> |
2276 |
2272 |
2277 attribute_setup %gray my_sym = |
2273 attribute_setup %gray my_sym = |
2278 {* Scan.succeed my_symmetric *} "applying the sym rule" |
2274 \<open>Scan.succeed my_symmetric\<close> "applying the sym rule" |
2279 |
2275 |
2280 text {* |
2276 text \<open> |
2281 Inside the @{text "\<verbopen> \<dots> \<verbclose>"}, we have to specify a parser |
2277 Inside the \<open>\<verbopen> \<dots> \<verbclose>\<close>, we have to specify a parser |
2282 for the theorem attribute. Since the attribute does not expect any further |
2278 for the theorem attribute. Since the attribute does not expect any further |
2283 arguments (unlike @{text "[THEN \<dots>]"}, for instance), we use the parser @{ML |
2279 arguments (unlike \<open>[THEN \<dots>]\<close>, for instance), we use the parser @{ML |
2284 Scan.succeed}. An example for the attribute @{text "[my_sym]"} is the proof |
2280 Scan.succeed}. An example for the attribute \<open>[my_sym]\<close> is the proof |
2285 *} |
2281 \<close> |
2286 |
2282 |
2287 lemma test[my_sym]: "2 = Suc (Suc 0)" by simp |
2283 lemma test[my_sym]: "2 = Suc (Suc 0)" by simp |
2288 |
2284 |
2289 text {* |
2285 text \<open> |
2290 which stores the theorem @{thm test} under the name @{thm [source] test}. You |
2286 which stores the theorem @{thm test} under the name @{thm [source] test}. You |
2291 can see this, if you query the lemma: |
2287 can see this, if you query the lemma: |
2292 |
2288 |
2293 \begin{isabelle} |
2289 \begin{isabelle} |
2294 \isacommand{thm}~@{text "test"}\\ |
2290 \isacommand{thm}~\<open>test\<close>\\ |
2295 @{text "> "}~@{thm test} |
2291 \<open>> \<close>~@{thm test} |
2296 \end{isabelle} |
2292 \end{isabelle} |
2297 |
2293 |
2298 We can also use the attribute when referring to this theorem: |
2294 We can also use the attribute when referring to this theorem: |
2299 |
2295 |
2300 \begin{isabelle} |
2296 \begin{isabelle} |
2301 \isacommand{thm}~@{text "test[my_sym]"}\\ |
2297 \isacommand{thm}~\<open>test[my_sym]\<close>\\ |
2302 @{text "> "}~@{thm test[my_sym]} |
2298 \<open>> \<close>~@{thm test[my_sym]} |
2303 \end{isabelle} |
2299 \end{isabelle} |
2304 |
2300 |
2305 An alternative for setting up an attribute is the function @{ML_ind setup in Attrib}. |
2301 An alternative for setting up an attribute is the function @{ML_ind setup in Attrib}. |
2306 So instead of using \isacommand{attribute\_setup}, you can also set up the |
2302 So instead of using \isacommand{attribute\_setup}, you can also set up the |
2307 attribute as follows: |
2303 attribute as follows: |
2308 *} |
2304 \<close> |
2309 |
2305 |
2310 ML %grayML{*Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric) |
2306 ML %grayML\<open>Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric) |
2311 "applying the sym rule" *} |
2307 "applying the sym rule"\<close> |
2312 |
2308 |
2313 text {* |
2309 text \<open> |
2314 This gives a function from @{ML_type "theory -> theory"}, which |
2310 This gives a function from @{ML_type "theory -> theory"}, which |
2315 can be used for example with \isacommand{setup} or with |
2311 can be used for example with \isacommand{setup} or with |
2316 @{ML "Context.>> o Context.map_theory"}.\footnote{\bf FIXME: explain what happens here.} |
2312 @{ML "Context.>> o Context.map_theory"}.\footnote{\bf FIXME: explain what happens here.} |
2317 |
2313 |
2318 As an example of a slightly more complicated theorem attribute, we implement |
2314 As an example of a slightly more complicated theorem attribute, we implement |
2319 our own version of @{text "[THEN \<dots>]"}. This attribute will take a list of theorems |
2315 our own version of \<open>[THEN \<dots>]\<close>. This attribute will take a list of theorems |
2320 as argument and resolve the theorem with this list (one theorem |
2316 as argument and resolve the theorem with this list (one theorem |
2321 after another). The code for this attribute is |
2317 after another). The code for this attribute is |
2322 *} |
2318 \<close> |
2323 |
2319 |
2324 ML %grayML{*fun MY_THEN thms = |
2320 ML %grayML\<open>fun MY_THEN thms = |
2325 let |
2321 let |
2326 fun RS_rev thm1 thm2 = thm2 RS thm1 |
2322 fun RS_rev thm1 thm2 = thm2 RS thm1 |
2327 in |
2323 in |
2328 Thm.rule_attribute [] (fn _ => fn thm => fold RS_rev thms thm) |
2324 Thm.rule_attribute [] (fn _ => fn thm => fold RS_rev thms thm) |
2329 end*} |
2325 end\<close> |
2330 |
2326 |
2331 text {* |
2327 text \<open> |
2332 where for convenience we define the reverse and curried version of @{ML RS}. |
2328 where for convenience we define the reverse and curried version of @{ML RS}. |
2333 The setup of this theorem attribute uses the parser @{ML thms in Attrib}, |
2329 The setup of this theorem attribute uses the parser @{ML thms in Attrib}, |
2334 which parses a list of theorems. |
2330 which parses a list of theorems. |
2335 *} |
2331 \<close> |
2336 |
2332 |
2337 attribute_setup %gray MY_THEN = {* Attrib.thms >> MY_THEN *} |
2333 attribute_setup %gray MY_THEN = \<open>Attrib.thms >> MY_THEN\<close> |
2338 "resolving the list of theorems with the theorem" |
2334 "resolving the list of theorems with the theorem" |
2339 |
2335 |
2340 text {* |
2336 text \<open> |
2341 You can, for example, use this theorem attribute to turn an equation into a |
2337 You can, for example, use this theorem attribute to turn an equation into a |
2342 meta-equation: |
2338 meta-equation: |
2343 |
2339 |
2344 \begin{isabelle} |
2340 \begin{isabelle} |
2345 \isacommand{thm}~@{text "test[MY_THEN eq_reflection]"}\\ |
2341 \isacommand{thm}~\<open>test[MY_THEN eq_reflection]\<close>\\ |
2346 @{text "> "}~@{thm test[MY_THEN eq_reflection]} |
2342 \<open>> \<close>~@{thm test[MY_THEN eq_reflection]} |
2347 \end{isabelle} |
2343 \end{isabelle} |
2348 |
2344 |
2349 If you need the symmetric version as a meta-equation, you can write |
2345 If you need the symmetric version as a meta-equation, you can write |
2350 |
2346 |
2351 \begin{isabelle} |
2347 \begin{isabelle} |
2352 \isacommand{thm}~@{text "test[MY_THEN sym eq_reflection]"}\\ |
2348 \isacommand{thm}~\<open>test[MY_THEN sym eq_reflection]\<close>\\ |
2353 @{text "> "}~@{thm test[MY_THEN sym eq_reflection]} |
2349 \<open>> \<close>~@{thm test[MY_THEN sym eq_reflection]} |
2354 \end{isabelle} |
2350 \end{isabelle} |
2355 |
2351 |
2356 It is also possible to combine different theorem attributes, as in: |
2352 It is also possible to combine different theorem attributes, as in: |
2357 |
2353 |
2358 \begin{isabelle} |
2354 \begin{isabelle} |
2359 \isacommand{thm}~@{text "test[my_sym, MY_THEN eq_reflection]"}\\ |
2355 \isacommand{thm}~\<open>test[my_sym, MY_THEN eq_reflection]\<close>\\ |
2360 @{text "> "}~@{thm test[my_sym, MY_THEN eq_reflection]} |
2356 \<open>> \<close>~@{thm test[my_sym, MY_THEN eq_reflection]} |
2361 \end{isabelle} |
2357 \end{isabelle} |
2362 |
2358 |
2363 However, here also a weakness of the concept |
2359 However, here also a weakness of the concept |
2364 of theorem attributes shows through: since theorem attributes can be |
2360 of theorem attributes shows through: since theorem attributes can be |
2365 arbitrary functions, they do not commute in general. If you try |
2361 arbitrary functions, they do not commute in general. If you try |
2366 |
2362 |
2367 \begin{isabelle} |
2363 \begin{isabelle} |
2368 \isacommand{thm}~@{text "test[MY_THEN eq_reflection, my_sym]"}\\ |
2364 \isacommand{thm}~\<open>test[MY_THEN eq_reflection, my_sym]\<close>\\ |
2369 @{text "> "}~@{text "exception THM 1 raised: RSN: no unifiers"} |
2365 \<open>> \<close>~\<open>exception THM 1 raised: RSN: no unifiers\<close> |
2370 \end{isabelle} |
2366 \end{isabelle} |
2371 |
2367 |
2372 you get an exception indicating that the theorem @{thm [source] sym} |
2368 you get an exception indicating that the theorem @{thm [source] sym} |
2373 does not resolve with meta-equations. |
2369 does not resolve with meta-equations. |
2374 |
2370 |
2375 The purpose of @{ML_ind rule_attribute in Thm} is to directly manipulate |
2371 The purpose of @{ML_ind rule_attribute in Thm} is to directly manipulate |
2376 theorems. Another usage of theorem attributes is to add and delete theorems |
2372 theorems. Another usage of theorem attributes is to add and delete theorems |
2377 from stored data. For example the theorem attribute @{text "[simp]"} adds |
2373 from stored data. For example the theorem attribute \<open>[simp]\<close> adds |
2378 or deletes a theorem from the current simpset. For these applications, you |
2374 or deletes a theorem from the current simpset. For these applications, you |
2379 can use @{ML_ind declaration_attribute in Thm}. To illustrate this function, |
2375 can use @{ML_ind declaration_attribute in Thm}. To illustrate this function, |
2380 let us introduce a theorem list. |
2376 let us introduce a theorem list. |
2381 *} |
2377 \<close> |
2382 |
2378 |
2383 ML %grayML{*structure MyThms = Named_Thms |
2379 ML %grayML\<open>structure MyThms = Named_Thms |
2384 (val name = @{binding "attr_thms"} |
2380 (val name = @{binding "attr_thms"} |
2385 val description = "Theorems for an Attribute") *} |
2381 val description = "Theorems for an Attribute")\<close> |
2386 |
2382 |
2387 text {* |
2383 text \<open> |
2388 We are going to modify this list by adding and deleting theorems. |
2384 We are going to modify this list by adding and deleting theorems. |
2389 For this we use the two functions @{ML MyThms.add_thm} and |
2385 For this we use the two functions @{ML MyThms.add_thm} and |
2390 @{ML MyThms.del_thm}. You can turn them into attributes |
2386 @{ML MyThms.del_thm}. You can turn them into attributes |
2391 with the code |
2387 with the code |
2392 *} |
2388 \<close> |
2393 |
2389 |
2394 ML %grayML{*val my_add = Thm.declaration_attribute MyThms.add_thm |
2390 ML %grayML\<open>val my_add = Thm.declaration_attribute MyThms.add_thm |
2395 val my_del = Thm.declaration_attribute MyThms.del_thm *} |
2391 val my_del = Thm.declaration_attribute MyThms.del_thm\<close> |
2396 |
2392 |
2397 text {* |
2393 text \<open> |
2398 and set up the attributes as follows |
2394 and set up the attributes as follows |
2399 *} |
2395 \<close> |
2400 |
2396 |
2401 attribute_setup %gray my_thms = {* Attrib.add_del my_add my_del *} |
2397 attribute_setup %gray my_thms = \<open>Attrib.add_del my_add my_del\<close> |
2402 "maintaining a list of my_thms" |
2398 "maintaining a list of my_thms" |
2403 |
2399 |
2404 text {* |
2400 text \<open> |
2405 The parser @{ML_ind add_del in Attrib} is a predefined parser for |
2401 The parser @{ML_ind add_del in Attrib} is a predefined parser for |
2406 adding and deleting lemmas. Now if you prove the next lemma |
2402 adding and deleting lemmas. Now if you prove the next lemma |
2407 and attach to it the attribute @{text "[my_thms]"} |
2403 and attach to it the attribute \<open>[my_thms]\<close> |
2408 *} |
2404 \<close> |
2409 |
2405 |
2410 lemma trueI_2[my_thms]: "True" by simp |
2406 lemma trueI_2[my_thms]: "True" by simp |
2411 |
2407 |
2412 text {* |
2408 text \<open> |
2413 then you can see it is added to the initially empty list. |
2409 then you can see it is added to the initially empty list. |
2414 |
2410 |
2415 @{ML_response_fake [display,gray] |
2411 @{ML_response_fake [display,gray] |
2416 "MyThms.get @{context}" |
2412 "MyThms.get @{context}" |
2417 "[\"True\"]"} |
2413 "[\"True\"]"} |
2418 |
2414 |
2419 You can also add theorems using the command \isacommand{declare}. |
2415 You can also add theorems using the command \isacommand{declare}. |
2420 *} |
2416 \<close> |
2421 |
2417 |
2422 declare test[my_thms] trueI_2[my_thms add] |
2418 declare test[my_thms] trueI_2[my_thms add] |
2423 |
2419 |
2424 text {* |
2420 text \<open> |
2425 With this attribute, the @{text "add"} operation is the default and does |
2421 With this attribute, the \<open>add\<close> operation is the default and does |
2426 not need to be explicitly given. These three declarations will cause the |
2422 not need to be explicitly given. These three declarations will cause the |
2427 theorem list to be updated as: |
2423 theorem list to be updated as: |
2428 |
2424 |
2429 @{ML_response_fake [display,gray] |
2425 @{ML_response_fake [display,gray] |
2430 "MyThms.get @{context}" |
2426 "MyThms.get @{context}" |
2431 "[\"True\", \"Suc (Suc 0) = 2\"]"} |
2427 "[\"True\", \"Suc (Suc 0) = 2\"]"} |
2432 |
2428 |
2433 The theorem @{thm [source] trueI_2} only appears once, since the |
2429 The theorem @{thm [source] trueI_2} only appears once, since the |
2434 function @{ML_ind add_thm in Thm} tests for duplicates, before extending |
2430 function @{ML_ind add_thm in Thm} tests for duplicates, before extending |
2435 the list. Deletion from the list works as follows: |
2431 the list. Deletion from the list works as follows: |
2436 *} |
2432 \<close> |
2437 |
2433 |
2438 declare test[my_thms del] |
2434 declare test[my_thms del] |
2439 |
2435 |
2440 text {* After this, the theorem list is again: |
2436 text \<open>After this, the theorem list is again: |
2441 |
2437 |
2442 @{ML_response_fake [display,gray] |
2438 @{ML_response_fake [display,gray] |
2443 "MyThms.get @{context}" |
2439 "MyThms.get @{context}" |
2444 "[\"True\"]"} |
2440 "[\"True\"]"} |
2445 |
2441 |
2446 We used in this example two functions declared as @{ML_ind |
2442 We used in this example two functions declared as @{ML_ind |
2447 declaration_attribute in Thm}, but there can be any number of them. We just |
2443 declaration_attribute in Thm}, but there can be any number of them. We just |
2448 have to change the parser for reading the arguments accordingly. |
2444 have to change the parser for reading the arguments accordingly. |
2449 |
2445 |
2450 \footnote{\bf FIXME What are: @{text "theory_attributes"}, @{text "proof_attributes"}?} |
2446 \footnote{\bf FIXME What are: \<open>theory_attributes\<close>, \<open>proof_attributes\<close>?} |
2451 \footnote{\bf FIXME readmore} |
2447 \footnote{\bf FIXME readmore} |
2452 |
2448 |
2453 \begin{readmore} |
2449 \begin{readmore} |
2454 FIXME: @{ML_file "Pure/more_thm.ML"}; parsers for attributes is in |
2450 FIXME: @{ML_file "Pure/more_thm.ML"}; parsers for attributes is in |
2455 @{ML_file "Pure/Isar/attrib.ML"}...also explained in the chapter about |
2451 @{ML_file "Pure/Isar/attrib.ML"}...also explained in the chapter about |
2456 parsing. |
2452 parsing. |
2457 \end{readmore} |
2453 \end{readmore} |
2458 *} |
2454 \<close> |
2459 |
2455 |
2460 section {* Pretty-Printing\label{sec:pretty} *} |
2456 section \<open>Pretty-Printing\label{sec:pretty}\<close> |
2461 |
2457 |
2462 text {* |
2458 text \<open> |
2463 So far we printed out only plain strings without any formatting except for |
2459 So far we printed out only plain strings without any formatting except for |
2464 occasional explicit line breaks using @{text [quotes] "\\n"}. This is |
2460 occasional explicit line breaks using @{text [quotes] "\\n"}. This is |
2465 sufficient for ``quick-and-dirty'' printouts. For something more |
2461 sufficient for ``quick-and-dirty'' printouts. For something more |
2466 sophisticated, Isabelle includes an infrastructure for properly formatting |
2462 sophisticated, Isabelle includes an infrastructure for properly formatting |
2467 text. Most of its functions do not operate on @{ML_type string}s, but on |
2463 text. Most of its functions do not operate on @{ML_type string}s, but on |