938 section {* New Commands\label{sec:newcommand} *} |
939 section {* New Commands\label{sec:newcommand} *} |
939 |
940 |
940 text {* |
941 text {* |
941 Often new commands, for example for providing new definitional principles, |
942 Often new commands, for example for providing new definitional principles, |
942 need to be implemented. While this is not difficult on the ML-level and |
943 need to be implemented. While this is not difficult on the ML-level and |
943 jEdit, in order to be compatible, new commands need also to be recognised |
944 jEdit, in order to be backwards compatible, new commands need also to be recognised |
944 by ProofGeneral. This results in some subtle configuration issues, which we will |
945 by Proof-General. This results in some subtle configuration issues, which we will |
945 explain in the next section. Here we just describe how to define new commands |
946 explain in the next section. Here we just describe how to define new commands |
946 to work with jEdit. |
947 to work with jEdit. |
947 |
948 |
948 Let us start with a ``silly'' command that does nothing |
949 Let us start with a ``silly'' command that does nothing at all. We |
949 at all. We shall name this command \isacommand{foobar}. On the ML-level it can be |
950 shall name this command \isacommand{foobar}. Before you can |
950 defined as: |
951 implement any new command, you have to ``announce'' it in the |
951 *} |
952 \isacommand{keyword}-section of theory header. For \isacommand{foobar} |
952 |
953 we need to write something like |
953 ML %grayML{*let |
|
954 val do_nothing = Scan.succeed (Local_Theory.background_theory I) |
|
955 val kind = Keyword.thy_decl |
|
956 in |
|
957 Outer_Syntax.local_theory ("foobar", kind) |
|
958 "description of foobar" |
|
959 do_nothing |
|
960 end *} |
|
961 |
|
962 text {* |
|
963 The crucial function @{ML_ind local_theory in Outer_Syntax} expects a name for the command, |
|
964 a kind indicator (which we will explain later more thoroughly), a |
|
965 short description and a |
|
966 parser producing a local theory transition (its purpose will also explained |
|
967 later). Before you can use any new command, you have to ``announce'' it in the |
|
968 \isacommand{keyword}-section of theory header. In our running example we need |
|
969 to write |
|
970 |
954 |
971 \begin{graybox} |
955 \begin{graybox} |
972 \isacommand{theory}~@{text Foo}\\ |
956 \isacommand{theory}~@{text Foo}\\ |
973 \isacommand{imports}~@{text Main}\\ |
957 \isacommand{imports}~@{text Main}\\ |
974 \isacommand{keywords} @{text [quotes] "foobar"} @{text "::"} @{text "thy_decl"}\\ |
958 \isacommand{keywords} @{text [quotes] "foobar"} @{text "::"} @{text "thy_decl"}\\ |
975 ... |
959 ... |
976 \end{graybox} |
960 \end{graybox} |
977 |
961 |
978 whereby you have to declare again that the new keyword is of the appropriate |
962 whereby @{ML_ind "thy_decl" in Keyword} indicates the kind of the |
979 kind---for \isacommand{foobar} it is @{text "thy_decl"}. Another possible kind |
963 command. Another possible kind is @{text "thy_goal"}, or you can |
980 is @{text "thy_goal"} and also to omit the kind entirely, in which case you declare a |
964 also to omit the kind entirely, in which case you declare a keyword |
981 keyword (something that is part of a command). After you announced the new command, |
965 (something that is part of a command). |
982 you can type in your theory |
966 |
983 *} |
967 Now you can implement \isacommand{foobar} as: |
|
968 *} |
|
969 |
|
970 ML %grayML{*let |
|
971 val do_nothing = Scan.succeed (Local_Theory.background_theory I) |
|
972 in |
|
973 Outer_Syntax.local_theory @{command_spec "foobar"} |
|
974 "description of foobar" |
|
975 do_nothing |
|
976 end *} |
|
977 |
|
978 text {* |
|
979 The crucial function @{ML_ind local_theory in Outer_Syntax} expects |
|
980 the name for the command, a kind indicator, a short description and |
|
981 a parser producing a local theory transition (explained later). For the |
|
982 name and the kind, you can use the ML-antiquotation @{text "@{command_spec ...}"}. |
|
983 After this, you can write in your theory |
|
984 *} |
|
985 |
984 |
986 |
985 foobar |
987 foobar |
986 |
988 |
987 text {* |
989 |
|
990 text {* |
|
991 Remember that this only works in jEdit. In order to let Proof-General |
|
992 recognise this command, a keyword file needs to be generated (see next |
|
993 section). |
|
994 |
988 At the moment the command \isacommand{foobar} is not very useful. Let us |
995 At the moment the command \isacommand{foobar} is not very useful. Let us |
989 refine it a bit next by letting it take a proposition as argument and |
996 refine it a bit next by letting it take a proposition as argument and |
990 printing this proposition inside the tracing buffer. For this the crucial |
997 printing this proposition inside the tracing buffer. We announce the |
991 part of a command is the function that determines the behaviour |
998 command as |
992 of the command. In the code above we used a ``do-nothing''-function, which |
999 |
993 because of @{ML_ind succeed in Scan} does not parse any argument, but immediately |
1000 \begin{graybox} |
994 returns the simple function @{ML "Local_Theory.background_theory I"}. We can |
1001 \isacommand{keywords} @{text [quotes] "foobar_trace"} @{text "::"} @{text "thy_decl"} |
995 replace this code by a function that first parses a proposition (using the |
1002 \end{graybox} |
996 parser @{ML Parse.prop}), then prints out some tracing |
1003 |
997 information (using the function @{text trace_prop}) and |
1004 The crucial part of a command is the function that determines the |
998 finally does nothing. For this you can write: |
1005 behaviour of the command. In the code above we used a |
|
1006 ``do-nothing''-function, which because of the parser @{ML_ind succeed in Scan} |
|
1007 does not parse any argument, but immediately returns the simple |
|
1008 function @{ML "Local_Theory.background_theory I"}. We can replace |
|
1009 this code by a function that first parses a proposition (using the |
|
1010 parser @{ML Parse.prop}), then prints out some tracing information |
|
1011 (using the function @{text trace_prop}) and finally does |
|
1012 nothing. For this you can write: |
999 *} |
1013 *} |
1000 |
1014 |
1001 ML %grayML{*let |
1015 ML %grayML{*let |
1002 fun trace_prop str = |
1016 fun trace_prop str = |
1003 Local_Theory.background_theory (fn ctxt => (tracing str; ctxt)) |
1017 Local_Theory.background_theory (fn ctxt => (tracing str; ctxt)) |
1004 |
1018 in |
1005 val kind = Keyword.thy_decl |
1019 Outer_Syntax.local_theory @{command_spec "foobar_trace"} |
1006 in |
|
1007 Outer_Syntax.local_theory ("foobar_trace", kind) |
|
1008 "traces a proposition" |
1020 "traces a proposition" |
1009 (Parse.prop >> trace_prop) |
1021 (Parse.prop >> trace_prop) |
1010 end *} |
1022 end *} |
1011 |
1023 |
1012 text {* |
1024 text {* |
1013 The command is now \isacommand{foobar\_trace} and can be used to |
1025 The command is now \isacommand{foobar\_trace} and can be used to |
1014 see the proposition in the tracing buffer (remember you need to announce |
1026 see the proposition in the tracing buffer. |
1015 every new command in the header of the theory). |
|
1016 *} |
1027 *} |
1017 |
1028 |
1018 foobar_trace "True \<and> False" |
1029 foobar_trace "True \<and> False" |
1019 |
1030 |
1020 text {* |
1031 text {* |
1028 \isacommand{function}). To achieve this kind of behaviour, you have to use |
1039 \isacommand{function}). To achieve this kind of behaviour, you have to use |
1029 the kind indicator @{ML_ind thy_goal in Keyword} and the function @{ML |
1040 the kind indicator @{ML_ind thy_goal in Keyword} and the function @{ML |
1030 "local_theory_to_proof" in Outer_Syntax} to set up the command. |
1041 "local_theory_to_proof" in Outer_Syntax} to set up the command. |
1031 Below we show the command \isacommand{foobar\_goal} which takes a |
1042 Below we show the command \isacommand{foobar\_goal} which takes a |
1032 proposition as argument and then starts a proof in order to prove |
1043 proposition as argument and then starts a proof in order to prove |
1033 it. Therefore in Line 9, we set the kind indicator to @{ML thy_goal in |
1044 it. Therefore, we need to announce this command in the header |
1034 Keyword}. |
1045 as @{text "thy_goal"} |
|
1046 |
|
1047 \begin{graybox} |
|
1048 \isacommand{keywords} @{text [quotes] "foobar_goal"} @{text "::"} @{text "thy_goal"} |
|
1049 \end{graybox} |
|
1050 |
|
1051 Then we can write: |
1035 *} |
1052 *} |
1036 |
1053 |
1037 ML%linenosgray{*let |
1054 ML%linenosgray{*let |
1038 fun goal_prop str ctxt = |
1055 fun goal_prop str ctxt = |
1039 let |
1056 let |
1040 val prop = Syntax.read_prop ctxt str |
1057 val prop = Syntax.read_prop ctxt str |
1041 in |
1058 in |
1042 Proof.theorem NONE (K I) [[(prop, [])]] ctxt |
1059 Proof.theorem NONE (K I) [[(prop, [])]] ctxt |
1043 end |
1060 end |
1044 |
1061 in |
1045 val kind = Keyword.thy_goal |
1062 Outer_Syntax.local_theory_to_proof @{command_spec "foobar_goal"} |
1046 in |
|
1047 Outer_Syntax.local_theory_to_proof ("foobar_goal", kind) |
|
1048 "proves a proposition" |
1063 "proves a proposition" |
1049 (Parse.prop >> goal_prop) |
1064 (Parse.prop >> goal_prop) |
1050 end *} |
1065 end *} |
1051 |
1066 |
1052 text {* |
1067 text {* |
1074 apply(rule conjI) |
1089 apply(rule conjI) |
1075 apply(rule TrueI)+ |
1090 apply(rule TrueI)+ |
1076 done |
1091 done |
1077 |
1092 |
1078 text {* |
1093 text {* |
|
1094 The final new command we describe is |
|
1095 \isacommand{foobar\_proof}. Like \isacommand{lemma}, its purpose is |
|
1096 to take a proposition and open a corresponding proof-state that |
|
1097 allows us to give a proof for it. However, unlike |
|
1098 \isacommand{lemma}, the proposition will be given as an |
|
1099 ML-value. Such a command is quite useful during development |
|
1100 of a tool that generates a goal on the ML-level and you want to see |
|
1101 whether it is provable. In addition you also want that the proved |
|
1102 proposition can be given a lemma name that can be referenced later on. |
|
1103 |
|
1104 The first problem of this new command is to parse some text as |
|
1105 ML-source and then interpret it as a term. For the parsing we can |
|
1106 use the function @{ML_ind "ML_source" in Parse} in the structure |
|
1107 @{ML_struct Parse}. For running the ML-interpreter we need the |
|
1108 following scaffolding code. |
|
1109 *} |
|
1110 |
|
1111 ML %grayML{* |
|
1112 structure Result = Proof_Data ( |
|
1113 type T = unit -> term |
|
1114 fun init thy () = error "Result") |
|
1115 |
|
1116 val result_cookie = (Result.get, Result.put, "Result.put") *} |
|
1117 |
|
1118 text {* |
|
1119 With this in place we can write the code for \isacommand{foobar\_prove}. |
|
1120 *} |
|
1121 |
|
1122 ML %linenosgray{*let |
|
1123 fun after_qed thm_name thms lthy = |
|
1124 Local_Theory.note (thm_name, (flat thms)) lthy |> snd |
|
1125 |
|
1126 fun setup_proof (thm_name, (txt, pos)) lthy = |
|
1127 let |
|
1128 val trm = Code_Runtime.value lthy result_cookie ("", txt) |
|
1129 in |
|
1130 Proof.theorem NONE (after_qed thm_name) [[(trm, [])]] lthy |
|
1131 end |
|
1132 |
|
1133 val parser = Parse_Spec.opt_thm_name ":" -- Parse.ML_source |
|
1134 in |
|
1135 Outer_Syntax.local_theory_to_proof @{command_spec "foobar_prove"} |
|
1136 "proving a proposition" |
|
1137 (parser >> setup_proof) |
|
1138 end*} |
|
1139 |
|
1140 text {* |
|
1141 In Line 12, we implement a parser that first reads in an optional lemma name (terminated |
|
1142 by ``:'') and then some ML-code. The function in Lines 5 to 10 takes the ML |
|
1143 text and lets the ML-runtime evaluate it using the function @{ML_ind value in Code_Runtime} |
|
1144 in the structure @{ML_struct Code_Runtime}. Once the ML-text has been turned into a term, |
|
1145 the function @{ML theorem in Proof} opens a corresponding proof-state. This function takes the |
|
1146 function @{ML_text "after_qed"} as argument, whose purpose is to store the theorem, |
|
1147 once it is proven, under the user given name @{text "thm_name"}. |
|
1148 |
|
1149 We can now give take a term, for example |
|
1150 *} |
|
1151 |
|
1152 ML %grayML{*val prop_true = @{prop "True"}*} |
|
1153 |
|
1154 text {* |
|
1155 and give a proove for it using \isacommand{foobar\_prove}: |
|
1156 *} |
|
1157 |
|
1158 foobar_prove test: prop_true |
|
1159 apply(rule TrueI) |
|
1160 done |
|
1161 |
|
1162 text {* |
|
1163 Finally we can test whether the lemma has been stored under the given name. |
|
1164 |
|
1165 \begin{isabelle} |
|
1166 \isacommand{thm}~@{text "test"}\\ |
|
1167 @{text "> "}~@{thm TrueI} |
|
1168 \end{isabelle} |
|
1169 |
1079 While this is everything you have to do for a new command when using jEdit, |
1170 While this is everything you have to do for a new command when using jEdit, |
1080 things are not as simple when using Emacs and ProofGeneral. We explain the details |
1171 things are not as simple when using Emacs and ProofGeneral. We explain the details |
1081 next. |
1172 next. |
1082 *} |
1173 *} |
1083 |
1174 |