diff -r be23597e81db -r f875a25aa72d ProgTutorial/Tactical.thy --- a/ProgTutorial/Tactical.thy Fri May 17 07:29:51 2019 +0200 +++ b/ProgTutorial/Tactical.thy Fri May 17 10:38:01 2019 +0200 @@ -48,17 +48,17 @@ This proof translates to the following ML-code. @{ML_matchresult_fake [display,gray] -"let +\let val ctxt = @{context} - val goal = @{prop \"P \ Q \ Q \ P\"} + val goal = @{prop "P \ Q \ Q \ P"} in - Goal.prove ctxt [\"P\", \"Q\"] [] goal + Goal.prove ctxt ["P", "Q"] [] goal (fn _ => eresolve_tac @{context} [@{thm disjE}] 1 THEN resolve_tac @{context} [@{thm disjI2}] 1 THEN assume_tac @{context} 1 THEN resolve_tac @{context} [@{thm disjI1}] 1 THEN assume_tac @{context} 1) -end" "?P \ ?Q \ ?Q \ ?P"} +end\ \?P \ ?Q \ ?Q \ ?P\} To start the proof, the function @{ML_ind prove in Goal} sets up a goal state for proving the goal @{prop "P \ Q \ Q \ P"}. We can give this @@ -764,16 +764,16 @@ The function @{ML_ind RS in Drule}, for example, does this. @{ML_matchresult_fake [display,gray] - "@{thm disjI1} RS @{thm conjI}" "\?P1; ?Q\ \ (?P1 \ ?Q1) \ ?Q"} + \@{thm disjI1} RS @{thm conjI}\ \\?P1; ?Q\ \ (?P1 \ ?Q1) \ ?Q\} In this example it instantiates the first premise of the \conjI\-theorem with the theorem \disjI1\. If the instantiation is impossible, as in the case of @{ML_matchresult_fake_both [display,gray] - "@{thm conjI} RS @{thm mp}" -"*** Exception- THM (\"RSN: no unifiers\", 1, -[\"\?P; ?Q\ \ ?P \ ?Q\", \"\?P \ ?Q; ?P\ \ ?Q\"]) raised"} + \@{thm conjI} RS @{thm mp}\ +\*** Exception- THM ("RSN: no unifiers", 1, +["\?P; ?Q\ \ ?P \ ?Q", "\?P \ ?Q; ?P\ \ ?Q"]) raised\} then the function raises an exception. The function @{ML_ind RSN in Drule} is similar to @{ML RS}, but takes an additional number as argument. This @@ -783,8 +783,8 @@ the function @{ML_ind MRS in Drule}: @{ML_matchresult_fake [display,gray] - "[@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI}" - "\?P2; ?Q1\ \ (?P2 \ ?Q2) \ (?P1 \ ?Q1)"} + \[@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI}\ + \\?P2; ?Q1\ \ (?P2 \ ?Q2) \ (?P1 \ ?Q1)\} If you need to instantiate lists of theorems, you can use the functions @{ML_ind RL in Drule} and @{ML_ind OF in Drule}. For @@ -792,16 +792,16 @@ instantiated with every theorem in the first. @{ML_matchresult_fake [display,gray] -"let +\let val list1 = [@{thm impI}, @{thm disjI2}] val list2 = [@{thm conjI}, @{thm disjI1}] in list1 RL list2 -end" -"[\?P1 \ ?Q1; ?Q\ \ (?P1 \ ?Q1) \ ?Q, +end\ +\[\?P1 \ ?Q1; ?Q\ \ (?P1 \ ?Q1) \ ?Q, \?Q1; ?Q\ \ (?P1 \ ?Q1) \ ?Q, (?P1 \ ?Q1) \ (?P1 \ ?Q1) \ ?Q, - ?Q1 \ (?P1 \ ?Q1) \ ?Q]"} + ?Q1 \ (?P1 \ ?Q1) \ ?Q]\} \begin{readmore} The combinators for instantiating theorems with other theorems are @@ -981,7 +981,7 @@ There is even another way of implementing this tactic: in automatic proof procedures (in contrast to tactics that might be called by the user) there are often long lists of tactics that are applied to the first - subgoal. Instead of writing the code above and then calling @{ML "foo_tac'' @{context} 1"}, + subgoal. Instead of writing the code above and then calling @{ML \foo_tac'' @{context} 1\}, you can also just write \ @@ -1097,7 +1097,7 @@ convention therefore, tactics visible to the user should either change something or fail. - To comply with this convention, we could simply delete the @{ML "K all_tac"} + To comply with this convention, we could simply delete the @{ML \K all_tac\} in @{ML select_tac'} or delete @{ML TRY} from @{ML select_tac''}. But for the sake of argument, let us suppose that this deletion is \emph{not} an option. In such cases, you can use the combinator @{ML_ind CHANGED in @@ -1459,10 +1459,10 @@ empty simpset, i.e., @{ML_ind empty_ss in Raw_Simplifier} @{ML_matchresult_fake [display,gray] - "print_ss @{context} empty_ss" -"Simplification rules: + \print_ss @{context} empty_ss\ +\Simplification rules: Congruences rules: -Simproc patterns:"} +Simproc patterns:\} you can see it contains nothing. This simpset is usually not useful, except as a building block to build bigger simpsets. For example you can add to @{ML empty_ss} @@ -1475,11 +1475,11 @@ Printing then out the components of the simpset gives: @{ML_matchresult_fake [display,gray] - "print_ss @{context} (Raw_Simplifier.simpset_of ss1)" -"Simplification rules: + \print_ss @{context} (Raw_Simplifier.simpset_of ss1)\ +\Simplification rules: ??.unknown: A - B \ C \ A - B \ (A - C) Congruences rules: -Simproc patterns:"} +Simproc patterns:\} \footnote{\bf FIXME: Why does it print out ??.unknown} @@ -1492,13 +1492,13 @@ gives @{ML_matchresult_fake [display,gray] - "print_ss @{context} (Raw_Simplifier.simpset_of ss2)" -"Simplification rules: + \print_ss @{context} (Raw_Simplifier.simpset_of ss2)\ +\Simplification rules: ??.unknown: A - B \ C \ A - B \ (A - C) Congruences rules: Complete_Lattices.Inf_class.INFIMUM: \A1 = B1; \x. x \ B1 =simp=> C1 x = D1 x\ \ INFIMUM A1 C1 \ INFIMUM B1 D1 -Simproc patterns:"} +Simproc patterns:\} Notice that we had to add these lemmas as meta-equations. The @{ML empty_ss} expects this form of the simplification and congruence rules. This is @@ -1509,10 +1509,10 @@ HOL_basic_ss in Simpdata}. While printing out the components of this simpset @{ML_matchresult_fake [display,gray] - "print_ss @{context} HOL_basic_ss" -"Simplification rules: + \print_ss @{context} HOL_basic_ss\ +\Simplification rules: Congruences rules: -Simproc patterns:"} +Simproc patterns:\} also produces ``nothing'', the printout is somewhat misleading. In fact the @{ML HOL_basic_ss} is setup so that it can solve goals of the @@ -1543,8 +1543,8 @@ connectives in HOL. @{ML_matchresult_fake [display,gray] - "print_ss @{context} HOL_ss" -"Simplification rules: + \print_ss @{context} HOL_ss\ +\Simplification rules: Pure.triv_forall_equality: (\x. PROP V) \ PROP V HOL.the_eq_trivial: THE x. x = y \ y HOL.the_sym_eq_trivial: THE ya. y = ya \ y @@ -1554,7 +1554,7 @@ \ (PROP P =simp=> PROP Q) \ (PROP P' =simp=> PROP Q') op -->: \P \ P'; P' \ Q \ Q'\ \ P \ Q \ P' \ Q' Simproc patterns: - \"} + \\} \begin{readmore} The simplifier for HOL is set up in @{ML_file "HOL/Tools/simpdata.ML"}. @@ -1755,7 +1755,7 @@ (FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy) - (FIXME: explain @{ML simplify} and @{ML "Simplifier.rewrite_rule"} etc.) + (FIXME: explain @{ML simplify} and @{ML \Simplifier.rewrite_rule\} etc.) \ @@ -2065,29 +2065,29 @@ instance of the (meta)reflexivity theorem. For example: @{ML_matchresult_fake [display,gray] - "Conv.all_conv @{cterm \"Foo \ Bar\"}" - "Foo \ Bar \ Foo \ Bar"} + \Conv.all_conv @{cterm "Foo \ Bar"}\ + \Foo \ Bar \ Foo \ Bar\} Another simple conversion is @{ML_ind no_conv in Conv} which always raises the exception @{ML CTERM}. @{ML_matchresult_fake [display,gray] - "Conv.no_conv @{cterm True}" - "*** Exception- CTERM (\"no conversion\", []) raised"} + \Conv.no_conv @{cterm True}\ + \*** Exception- CTERM ("no conversion", []) raised\} A more interesting conversion is the function @{ML_ind beta_conversion in Thm}: it produces a meta-equation between a term and its beta-normal form. For example @{ML_matchresult_fake [display,gray] - "let - val add = @{cterm \"\x y. x + (y::nat)\"} - val two = @{cterm \"2::nat\"} - val ten = @{cterm \"10::nat\"} + \let + val add = @{cterm "\x y. x + (y::nat)"} + val two = @{cterm "2::nat"} + val ten = @{cterm "10::nat"} val ctrm = Thm.apply (Thm.apply add two) ten in Thm.beta_conversion true ctrm -end" - "((\x y. x + y) 2) 10 \ 2 + 10"} +end\ + \((\x y. x + y) 2) 10 \ 2 + 10\} If you run this example, you will notice that the actual response is the seemingly nonsensical @{term @@ -2097,25 +2097,25 @@ we obtain the expected result. @{ML_matchresult [display,gray] -"let - val add = @{cterm \"\x y. x + (y::nat)\"} - val two = @{cterm \"2::nat\"} - val ten = @{cterm \"10::nat\"} +\let + val add = @{cterm "\x y. x + (y::nat)"} + val two = @{cterm "2::nat"} + val ten = @{cterm "10::nat"} val ctrm = Thm.apply (Thm.apply add two) ten in Thm.prop_of (Thm.beta_conversion true ctrm) -end" -"Const (\"Pure.eq\",_) $ - (Abs (\"x\",_,Abs (\"y\",_,_)) $_$_) $ - (Const (\"Groups.plus_class.plus\",_) $ _ $ _)"} +end\ +\Const ("Pure.eq",_) $ + (Abs ("x",_,Abs ("y",_,_)) $_$_) $ + (Const ("Groups.plus_class.plus",_) $ _ $ _)\} or in the pretty-printed form @{ML_matchresult_fake [display,gray] -"let - val add = @{cterm \"\x y. x + (y::nat)\"} - val two = @{cterm \"2::nat\"} - val ten = @{cterm \"10::nat\"} +\let + val add = @{cterm "\x y. x + (y::nat)"} + val two = @{cterm "2::nat"} + val ten = @{cterm "10::nat"} val ctrm = Thm.apply (Thm.apply add two) ten val ctxt = @{context} |> Config.put eta_contract false @@ -2124,8 +2124,8 @@ Thm.prop_of (Thm.beta_conversion true ctrm) |> pretty_term ctxt |> pwriteln -end" -"(\x y. x + y) 2 10 \ 2 + 10"} +end\ +\(\x y. x + y) 2 10 \ 2 + 10\} The argument @{ML true} in @{ML beta_conversion in Thm} indicates that the right-hand side should be fully beta-normalised. If instead @@ -2147,12 +2147,12 @@ to @{term "Foo \ Bar"}. The code is as follows. @{ML_matchresult_fake [display,gray] -"let - val ctrm = @{cterm \"True \ (Foo \ Bar)\"} +\let + val ctrm = @{cterm "True \ (Foo \ Bar)"} in Conv.rewr_conv @{thm true_conj1} ctrm -end" - "True \ (Foo \ Bar) \ Foo \ Bar"} +end\ + \True \ (Foo \ Bar) \ Foo \ Bar\} Note, however, that the function @{ML_ind rewr_conv in Conv} only rewrites the outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match @@ -2166,14 +2166,14 @@ which applies one conversion after another. For example @{ML_matchresult_fake [display,gray] -"let +\let val conv1 = Thm.beta_conversion false val conv2 = Conv.rewr_conv @{thm true_conj1} - val ctrm = Thm.apply @{cterm \"\x. x \ False\"} @{cterm \"True\"} + val ctrm = Thm.apply @{cterm "\x. x \ False"} @{cterm "True"} in (conv1 then_conv conv2) ctrm -end" - "(\x. x \ False) True \ False"} +end\ + \(\x. x \ False) True \ False\} where we first beta-reduce the term and then rewrite according to @{thm [source] true_conj1}. (When running this example recall the @@ -2183,14 +2183,14 @@ first one, and if it does not apply, tries the second. For example @{ML_matchresult_fake [display,gray] -"let +\let val conv = Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv - val ctrm1 = @{cterm \"True \ Q\"} - val ctrm2 = @{cterm \"P \ (True \ Q)\"} + val ctrm1 = @{cterm "True \ Q"} + val ctrm2 = @{cterm "P \ (True \ Q)"} in (conv ctrm1, conv ctrm2) -end" -"(True \ Q \ Q, P \ True \ Q \ P \ True \ Q)"} +end\ +\(True \ Q \ Q, P \ True \ Q \ P \ True \ Q)\} Here the conversion @{thm [source] true_conj1} only applies in the first case, but fails in the second. The whole conversion @@ -2200,13 +2200,13 @@ For example @{ML_matchresult_fake [display,gray] -"let +\let val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) - val ctrm = @{cterm \"True \ P\"} + val ctrm = @{cterm "True \ P"} in conv ctrm -end" - "True \ P \ True \ P"} +end\ + \True \ P \ True \ P\} Rewriting with more than one theorem can be done using the function @{ML_ind rewrs_conv in Conv} from the structure @{ML_structure Conv}. @@ -2221,13 +2221,13 @@ For example @{ML_matchresult_fake [display,gray] -"let +\let val conv = Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) - val ctrm = @{cterm \"P \ (True \ Q)\"} + val ctrm = @{cterm "P \ (True \ Q)"} in conv ctrm -end" -"P \ (True \ Q) \ P \ Q"} +end\ +\P \ (True \ Q) \ P \ Q\} The reason for this behaviour is that \(op \)\ expects two arguments. Therefore the term must be of the form \(Const \ $ t1) $ t2\. The @@ -2239,13 +2239,13 @@ abstraction. For example: @{ML_matchresult_fake [display,gray] -"let +\let val conv = Conv.rewr_conv @{thm true_conj1} - val ctrm = @{cterm \"\P. True \ (P \ Foo)\"} + val ctrm = @{cterm "\P. True \ (P \ Foo)"} in Conv.abs_conv (K conv) @{context} ctrm -end" - "\P. True \ (P \ Foo) \ \P. P \ Foo"} +end\ + \\P. True \ (P \ Foo) \ \P. P \ Foo\} Note that this conversion needs a context as an argument. We also give the conversion as \(K conv)\, which is a function that ignores its @@ -2280,13 +2280,13 @@ conversion in action, consider the following example: @{ML_matchresult_fake [display,gray] -"let +\let val conv = true_conj1_conv @{context} - val ctrm = @{cterm \"distinct [1::nat, x] \ True \ 1 \ x\"} + val ctrm = @{cterm "distinct [1::nat, x] \ True \ 1 \ x"} in conv ctrm -end" - "distinct [1, x] \ True \ 1 \ x \ distinct [1, x] \ 1 \ x"} +end\ + \distinct [1, x] \ True \ 1 \ x \ distinct [1, x] \ 1 \ x\} \ text \ @@ -2323,17 +2323,17 @@ two results are calculated. @{ML_matchresult_fake [display, gray] - "let + \let val ctxt = @{context} val conv = Conv.try_conv (Conv.rewrs_conv @{thms conj_assoc}) val conv_top = Conv.top_conv (K conv) ctxt val conv_bot = Conv.bottom_conv (K conv) ctxt - val ctrm = @{cterm \"(a \ (b \ c)) \ d\"} + val ctrm = @{cterm "(a \ (b \ c)) \ d"} in (conv_top ctrm, conv_bot ctrm) -end" - "(\"(a \ (b \ c)) \ d \ a \ (b \ (c \ d))\", - \"(a \ (b \ c)) \ d \ (a \ b) \ (c \ d)\")"} +end\ + \("(a \ (b \ c)) \ d \ a \ (b \ (c \ d))", + "(a \ (b \ c)) \ d \ (a \ b) \ (c \ d)")\} To see how much control you have over rewriting with conversions, let us make the task a bit more complicated by rewriting according to the rule @@ -2359,14 +2359,14 @@ @{ML_matchresult_fake [display,gray] -"let - val ctrm = @{cterm \"if P (True \ 1 \ (2::nat)) - then True \ True else True \ False\"} +\let + val ctrm = @{cterm "if P (True \ 1 \ (2::nat)) + then True \ True else True \ False"} in if_true1_conv @{context} ctrm -end" -"if P (True \ 1 \ 2) then True \ True else True \ False -\ if P (1 \ 2) then True \ True else True \ False"} +end\ +\if P (True \ 1 \ 2) then True \ True else True \ False +\ if P (1 \ 2) then True \ True else True \ False\} \ text \ @@ -2383,13 +2383,13 @@ new theorem as follows @{ML_matchresult_fake [display,gray] -"let +\let val conv = Conv.fconv_rule (true_conj1_conv @{context}) val thm = @{thm foo_test} in conv thm -end" - "?P \ \ ?P"} +end\ + \?P \ \ ?P\} Finally, Isabelle provides function @{ML_ind CONVERSION in Tactical} for turning conversions into tactics. This needs some predefined conversion @@ -2420,7 +2420,7 @@ Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)\ text \ - We call the conversions with the argument @{ML "~1"}. By this we + We call the conversions with the argument @{ML \~1\}. By this we analyse all parameters, all premises and the conclusion of a goal state. If we call @{ML concl_conv in Conv} with a non-negative number, say \n\, then this conversions will @@ -2466,8 +2466,8 @@ left-hand side in the right-hand side. @{ML_matchresult_fake [display,gray] - "Drule.abs_def @{thm id1_def}" - "id1 \ \x. x"} + \Drule.abs_def @{thm id1_def}\ + \id1 \ \x. x\} Unfortunately, Isabelle has no built-in function that transforms the theorems in the other direction. We can implement one using @@ -2514,8 +2514,8 @@ produce meta-variables for the theorem. An example is as follows. @{ML_matchresult_fake [display, gray] - "unabs_def @{context} @{thm id2_def}" - "id2 ?x1 \ ?x1"} + \unabs_def @{context} @{thm id2_def}\ + \id2 ?x1 \ ?x1\} \ text \