555 |
555 |
556 text {* |
556 text {* |
557 While antiquotations are very convenient for constructing terms, they can |
557 While antiquotations are very convenient for constructing terms, they can |
558 only construct fixed terms (remember they are ``linked'' at compile-time). |
558 only construct fixed terms (remember they are ``linked'' at compile-time). |
559 However, you often need to construct terms dynamically. For example, a |
559 However, you often need to construct terms dynamically. For example, a |
560 function that returns the implication @{text "\<And>(x::\<tau>). P x \<Longrightarrow> Q x"} taking |
560 function that returns the implication @{text "\<And>(x::nat). P x \<Longrightarrow> Q x"} taking |
561 @{term P}, @{term Q} and the type @{term "\<tau>"} as arguments can only be |
561 @{term P} and @{term Q} as arguments can only be written as: |
562 written as: |
562 |
563 |
563 *} |
564 *} |
564 |
565 |
565 ML{*fun make_imp P Q = |
566 ML{*fun make_imp P Q tau = |
|
567 let |
566 let |
568 val x = Free ("x", tau) |
567 val x = Free ("x", @{typ nat}) |
569 in |
568 in |
570 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
569 Logic.all x (Logic.mk_implies (P $ x, Q $ x)) |
571 end *} |
570 end *} |
572 |
571 |
573 text {* |
572 text {* |
574 The reason is that you cannot pass the arguments @{term P}, @{term Q} and |
573 The reason is that you cannot pass the arguments @{term P} and @{term Q} |
575 @{term "tau"} into an antiquotation. For example the following does \emph{not} work. |
574 into an antiquotation. For example the following does \emph{not} work. |
576 *} |
575 *} |
577 |
576 |
578 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *} |
577 ML{*fun make_wrong_imp P Q = @{prop "\<And>(x::nat). P x \<Longrightarrow> Q x"} *} |
579 |
578 |
580 text {* |
579 text {* |
581 To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} |
580 To see this apply @{text "@{term S}"} and @{text "@{term T}"} |
582 to both functions. With @{ML make_imp} we obtain the intended term involving |
581 to both functions. With @{ML make_imp} we obtain the intended term involving |
583 the given arguments |
582 the given arguments |
584 |
583 |
585 @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" |
584 @{ML_response [display,gray] "make_imp @{term S} @{term T}" |
586 "Const \<dots> $ |
585 "Const \<dots> $ |
587 Abs (\"x\", Type (\"nat\",[]), |
586 Abs (\"x\", Type (\"nat\",[]), |
588 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"} |
587 Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"} |
589 |
588 |
590 whereas with @{ML make_wrong_imp} we obtain a term involving the @{term "P"} |
589 whereas with @{ML make_wrong_imp} we obtain a term involving the @{term "P"} |
591 and @{text "Q"} from the antiquotation. |
590 and @{text "Q"} from the antiquotation. |
592 |
591 |
593 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" |
592 @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T}" |
594 "Const \<dots> $ |
593 "Const \<dots> $ |
595 Abs (\"x\", \<dots>, |
594 Abs (\"x\", \<dots>, |
596 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
595 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
597 (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"} |
596 (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"} |
598 |
597 |
599 (FIXME: handy functions for constructing terms: @{ML list_comb}, @{ML lambda}) |
598 (FIXME: handy functions for constructing terms: @{ML list_comb}, @{ML lambda}) |
600 |
599 *} |
601 |
600 |
602 Although types of terms can often be inferred, there are many |
601 |
603 situations where you need to construct types manually, especially |
602 text {* |
604 when defining constants. For example the function returning a function |
|
605 type is as follows: |
|
606 |
|
607 *} |
|
608 |
|
609 ML{*fun make_fun_type tau1 tau2 = Type ("fun", [tau1, tau2]) *} |
|
610 |
|
611 text {* This can be equally written with the combinator @{ML "-->"} as: *} |
|
612 |
|
613 ML{*fun make_fun_type tau1 tau2 = tau1 --> tau2 *} |
|
614 |
|
615 text {* |
|
616 A handy function for manipulating terms is @{ML map_types}: it takes a |
|
617 function and applies it to every type in a term. You can, for example, |
|
618 change every @{typ nat} in a term into an @{typ int} using the function: |
|
619 *} |
|
620 |
|
621 ML{*fun nat_to_int t = |
|
622 (case t of |
|
623 @{typ nat} => @{typ int} |
|
624 | Type (s, ts) => Type (s, map nat_to_int ts) |
|
625 | _ => t)*} |
|
626 |
|
627 text {* |
|
628 An example as follows: |
|
629 |
|
630 @{ML_response_fake [display,gray] |
|
631 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
|
632 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
|
633 $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"} |
|
634 |
|
635 \begin{readmore} |
603 \begin{readmore} |
636 There are many functions in @{ML_file "Pure/term.ML"}, @{ML_file "Pure/logic.ML"} and |
604 There are many functions in @{ML_file "Pure/term.ML"}, @{ML_file "Pure/logic.ML"} and |
637 @{ML_file "HOL/Tools/hologic.ML"} that make such manual constructions of terms |
605 @{ML_file "HOL/Tools/hologic.ML"} that make such manual constructions of terms |
638 and types easier.\end{readmore} |
606 and types easier.\end{readmore} |
639 |
607 |
750 strips off all qualifiers. |
718 strips off all qualifiers. |
751 |
719 |
752 \begin{readmore} |
720 \begin{readmore} |
753 Functions about naming are implemented in @{ML_file "Pure/General/name_space.ML"}; |
721 Functions about naming are implemented in @{ML_file "Pure/General/name_space.ML"}; |
754 functions about signatures in @{ML_file "Pure/sign.ML"}. |
722 functions about signatures in @{ML_file "Pure/sign.ML"}. |
755 |
|
756 \end{readmore} |
723 \end{readmore} |
|
724 |
|
725 Although types of terms can often be inferred, there are many |
|
726 situations where you need to construct types manually, especially |
|
727 when defining constants. For example the function returning a function |
|
728 type is as follows: |
|
729 |
|
730 *} |
|
731 |
|
732 ML{*fun make_fun_type tau1 tau2 = Type ("fun", [tau1, tau2]) *} |
|
733 |
|
734 text {* This can be equally written with the combinator @{ML "-->"} as: *} |
|
735 |
|
736 ML{*fun make_fun_type tau1 tau2 = tau1 --> tau2 *} |
|
737 |
|
738 text {* |
|
739 A handy function for manipulating terms is @{ML map_types}: it takes a |
|
740 function and applies it to every type in a term. You can, for example, |
|
741 change every @{typ nat} in a term into an @{typ int} using the function: |
|
742 *} |
|
743 |
|
744 ML{*fun nat_to_int t = |
|
745 (case t of |
|
746 @{typ nat} => @{typ int} |
|
747 | Type (s, ts) => Type (s, map nat_to_int ts) |
|
748 | _ => t)*} |
|
749 |
|
750 text {* |
|
751 An example as follows: |
|
752 |
|
753 @{ML_response_fake [display,gray] |
|
754 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
|
755 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
|
756 $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"} |
|
757 |
|
758 (FIXME: readmore about types) |
757 *} |
759 *} |
758 |
760 |
759 |
761 |
760 section {* Type-Checking *} |
762 section {* Type-Checking *} |
761 |
763 |
1181 section {* Setups (TBD) *} |
1183 section {* Setups (TBD) *} |
1182 |
1184 |
1183 text {* |
1185 text {* |
1184 In the previous section we used \isacommand{setup} in order to make |
1186 In the previous section we used \isacommand{setup} in order to make |
1185 a theorem attribute known to Isabelle. What happens behind the scenes |
1187 a theorem attribute known to Isabelle. What happens behind the scenes |
1186 is that \isacommand{setup} expects a functions from @{ML_type theory} |
1188 is that \isacommand{setup} expects a functions of type |
1187 to @{ML_type theory}: the input theory is the current theory and the |
1189 @{ML_type "theory -> theory"}: the input theory is the current theory and the |
1188 output the theory where the theory attribute has been stored. |
1190 output the theory where the theory attribute has been stored. |
1189 |
1191 |
1190 This is a fundamental principle in Isabelle. A similar situation occurs |
1192 This is a fundamental principle in Isabelle. A similar situation occurs |
1191 for example with declaring constants. The function that declares a |
1193 for example with declaring constants. The function that declares a |
1192 constant on the ML-level is @{ML Sign.add_consts_i}. Recall that ML-code |
1194 constant on the ML-level is @{ML Sign.add_consts_i}. |
1193 needs to be \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}. |
1195 If you write\footnote{Recall that ML-code needs to be |
1194 If you write |
1196 enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} |
1195 *} |
1197 *} |
1196 |
1198 |
1197 ML{*Sign.add_consts_i [(Binding.name "BAR", @{typ "nat"}, NoSyn)] @{theory} *} |
1199 ML{*Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] @{theory} *} |
1198 |
1200 |
1199 text {* |
1201 text {* |
1200 for declaring the constant @{text "BAR"} with type @{typ nat} and |
1202 for declaring the constant @{text "BAR"} with type @{typ nat} and |
1201 run the code, then you indeed obtain a theory as result. But if you |
1203 run the code, then you indeed obtain a theory as result. But if you |
1202 query the constant with \isacommand{term} |
1204 query the constant on the Isabelle level using the command \isacommand{term} |
1203 |
1205 |
1204 \begin{isabelle} |
1206 \begin{isabelle} |
1205 \isacommand{term}~@{text [quotes] "BAR"}\\ |
1207 \isacommand{term}~@{text [quotes] "BAR"}\\ |
1206 @{text "> \"BAR\" :: \"'a\""} |
1208 @{text "> \"BAR\" :: \"'a\""} |
1207 \end{isabelle} |
1209 \end{isabelle} |