diff -r be23597e81db -r f875a25aa72d ProgTutorial/First_Steps.thy --- a/ProgTutorial/First_Steps.thy Fri May 17 07:29:51 2019 +0200 +++ b/ProgTutorial/First_Steps.thy Fri May 17 10:38:01 2019 +0200 @@ -39,7 +39,7 @@ \begin{isabelle} \begin{graybox} \isacommand{ML}~\\\\isanewline - \hspace{5mm}@{ML "3 + 4"}\isanewline + \hspace{5mm}@{ML \3 + 4\}\isanewline \\\\isanewline \> 7\\smallskip \end{graybox} @@ -61,7 +61,7 @@ \begin{isabelle} \isacommand{lemma}~\test:\\isanewline \isacommand{shows}~@{text [quotes] "True"}\isanewline - \isacommand{ML\_prf}~\\\~@{ML "writeln \"Trivial!\""}~\\\\isanewline + \isacommand{ML\_prf}~\\\~@{ML \writeln "Trivial!"\}~\\\\isanewline \isacommand{oops} \end{isabelle} \end{quote} @@ -93,7 +93,7 @@ code. This can be done in a ``quick-and-dirty'' fashion using the function @{ML_ind writeln in Output}. For example - @{ML_matchresult_fake [display,gray] "writeln \"any string\"" "\"any string\""} + @{ML_matchresult_fake [display,gray] \writeln "any string"\ \"any string"\} will print out @{text [quotes] "any string"}. This function expects a string as argument. If you develop under @@ -110,9 +110,9 @@ for example: @{ML_matchresult_fake [display,gray] - "if 0 = 1 then true else (error \"foo\")" -"*** foo -***"} + \if 0 = 1 then true else (error "foo")\ +\*** foo +***\} This function raises the exception \ERROR\, which will then be displayed by the infrastructure indicating that it is an error by @@ -137,8 +137,8 @@ They can be used as follows @{ML_matchresult_fake [display,gray] - "pwriteln (pretty_term @{context} @{term \"1::nat\"})" - "\"1\""} + \pwriteln (pretty_term @{context} @{term "1::nat"})\ + \"1"\} If there is more than one term to be printed, you can use the function @{ML_ind commas in Pretty} and @{ML_ind block in Pretty} @@ -160,8 +160,8 @@ Now by using this context @{ML pretty_term} prints out @{ML_matchresult_fake [display, gray] - "pwriteln (pretty_term show_types_ctxt @{term \"(1::nat, x)\"})" - "(1::nat, x::'a)"} + \pwriteln (pretty_term show_types_ctxt @{term "(1::nat, x)"})\ + \(1::nat, x::'a)\} where \1\ and \x\ are displayed with their inferred types. Other configuration values that influence @@ -204,8 +204,8 @@ instantiation of \?P\ and \?Q\. @{ML_matchresult_fake [display, gray] - "pwriteln (pretty_thm @{context} @{thm conjI})" - "\?P; ?Q\ \ ?P \ ?Q"} + \pwriteln (pretty_thm @{context} @{thm conjI})\ + \\?P; ?Q\ \ ?P \ ?Q\} However, to improve the readability when printing theorems, we can switch off the question marks as follows: @@ -222,8 +222,8 @@ With this function, theorem @{thm [source] conjI} is now printed as follows: @{ML_matchresult_fake [display, gray] - "pwriteln (pretty_thm_no_vars @{context} @{thm conjI})" - "\P; Q\ \ P \ Q"} + \pwriteln (pretty_thm_no_vars @{context} @{thm conjI})\ + \\P; Q\ \ P \ Q\} Again the functions @{ML commas} and @{ML block in Pretty} help with printing more than one theorem. @@ -265,17 +265,17 @@ \emph{not} print out information as @{ML_matchresult_fake [display,gray] -"pwriteln (Pretty.str \"First half,\"); -pwriteln (Pretty.str \"and second half.\")" -"First half, -and second half."} +\pwriteln (Pretty.str "First half,"); +pwriteln (Pretty.str "and second half.")\ +\First half, +and second half.\} but as a single string with appropriate formatting. For example @{ML_matchresult_fake [display,gray] -"pwriteln (Pretty.str (\"First half,\" ^ \"\\n\" ^ \"and second half.\"))" -"First half, -and second half."} +\pwriteln (Pretty.str ("First half," ^ "\\n" ^ "and second half."))\ +\First half, +and second half.\} To ease this kind of string manipulations, there are a number of library functions in Isabelle. For example, the function @@ -283,9 +283,9 @@ and inserts newlines in between each element. @{ML_matchresult_fake [display, gray] - "pwriteln (Pretty.str (cat_lines [\"foo\", \"bar\"]))" - "foo -bar"} + \pwriteln (Pretty.str (cat_lines ["foo", "bar"]))\ + \foo +bar\} Section \ref{sec:pretty} will explain the infrastructure that Isabelle provides for more elaborate pretty printing. @@ -383,20 +383,20 @@ text \ This function takes a term and a context as arguments. If the term is of function - type, then @{ML "apply_fresh_args"} returns the term with distinct variables + type, then @{ML \apply_fresh_args\} returns the term with distinct variables applied to it. For example, below three variables are applied to the term @{term [show_types] "P::nat \ int \ unit \ bool"}: @{ML_matchresult_fake [display,gray] -"let - val trm = @{term \"P::nat \ int \ unit \ bool\"} +\let + val trm = @{term "P::nat \ int \ unit \ bool"} val ctxt = @{context} in apply_fresh_args trm ctxt |> pretty_term ctxt |> pwriteln -end" - "P z za zb"} +end\ + \P z za zb\} You can read off this behaviour from how @{ML apply_fresh_args} is coded: in Line 2, the function @{ML_ind fastype_of in Term} calculates the type of the @@ -415,15 +415,15 @@ tremendously to avoid any name clashes. Consider for example: @{ML_matchresult_fake [display,gray] -"let - val trm = @{term \"za::'a \ 'b \ 'c\"} +\let + val trm = @{term "za::'a \ 'b \ 'c"} val ctxt = @{context} in apply_fresh_args trm ctxt |> pretty_term ctxt |> pwriteln -end" - "za z zb"} +end\ + \za z zb\} where the \za\ is correctly avoided. @@ -444,7 +444,7 @@ \isacommand{setup}- or \isacommand{local\_setup}-command. These functions have to be of type @{ML_type "theory -> theory"}, respectively @{ML_type "local_theory -> local_theory"}. More than one such setup function - can be composed with @{ML "#>"}. Consider for example the following code, + can be composed with @{ML \#>\}. Consider for example the following code, where we store the theorems @{thm [source] conjI}, @{thm [source] conjunct1} and @{thm [source] conjunct2} under alternative names. \ @@ -463,7 +463,7 @@ @{ML_ind note in Local_Theory} in the structure @{ML_structure Local_Theory}; it stores a theorem under a name. In lines 5 to 6 we call this function to give alternative names for the three - theorems. The point of @{ML "#>"} is that you can sequence such function calls. + theorems. The point of @{ML \#>\} is that you can sequence such function calls. The remaining combinators we describe in this section add convenience for the ``waterfall method'' of writing functions. The combinator @{ML_ind tap @@ -501,9 +501,9 @@ text \ which takes \x\ as argument, and then increments \x\, but also keeps - \x\. The intermediate result is therefore the pair @{ML "(x + 1, x)" + \x\. The intermediate result is therefore the pair @{ML \(x + 1, x)\ for x}. After that, the function increments the right-hand component of the - pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. + pair. So finally the result will be @{ML \(x + 1, x + 1)\ for x}. The combinators @{ML_ind "|>>" in Basics} and @{ML_ind "||>" in Basics} are defined for functions manipulating pairs. The first applies the function to @@ -522,8 +522,8 @@ These two functions can, for example, be used to avoid explicit \lets\ for intermediate values in functions that return pairs. As an example, suppose you want to separate a list of integers into two lists according to a - threshold. If the threshold is @{ML "5"}, the list @{ML "[1,6,2,5,3,4]"} - should be separated as @{ML "([1,2,3,4], [6,5])"}. Such a function can be + threshold. If the threshold is @{ML \5\}, the list @{ML \[1,6,2,5,3,4]\} + should be separated as @{ML \([1,2,3,4], [6,5])\}. Such a function can be implemented as \ @@ -537,7 +537,7 @@ text \ where the return value of the recursive call is bound explicitly to - the pair @{ML "(los, grs)" for los grs}. However, this function + the pair @{ML \(los, grs)\ for los grs}. However, this function can be implemented more concisely as \ @@ -588,37 +588,37 @@ the value by one, but also nest the intermediate results to the left. For example @{ML_matchresult [display,gray] - "acc_incs 1" - "((((\"\", 1), 2), 3), 4)"} + \acc_incs 1\ + \(((("", 1), 2), 3), 4)\} You can continue this chain with: @{ML_matchresult [display,gray] - "acc_incs 1 ||>> (fn x => (x, x + 2))" - "(((((\"\", 1), 2), 3), 4), 6)"} + \acc_incs 1 ||>> (fn x => (x, x + 2))\ + \((((("", 1), 2), 3), 4), 6)\} An example where this combinator is useful is as follows @{ML_matchresult_fake [display, gray] - "let + \let val ((names1, names2), _) = @{context} - |> Variable.variant_fixes (replicate 4 \"x\") - ||>> Variable.variant_fixes (replicate 5 \"x\") + |> Variable.variant_fixes (replicate 4 "x") + ||>> Variable.variant_fixes (replicate 5 "x") in (names1, names2) -end" - "([\"x\", \"xa\", \"xb\", \"xc\"], [\"xd\", \"xe\", \"xf\", \"xg\", \"xh\"])"} +end\ + \(["x", "xa", "xb", "xc"], ["xd", "xe", "xf", "xg", "xh"])\} - Its purpose is to create nine variants of the string @{ML "\"x\""} so + Its purpose is to create nine variants of the string @{ML \"x"\} so that no variant will clash with another. Suppose for some reason we want to bind four variants to the lists @{ML_text "name1"} and the rest to @{ML_text "name2"}. In order to obtain non-clashing variants we have to thread the context through the function calls (the context records which variants have been previously created). - For the first call we can use @{ML "|>"}, but in the + For the first call we can use @{ML \|>\}, but in the second and any further call to @{ML_ind variant_fixes in Variable} we - have to use @{ML "||>>"} in order to account for the result(s) + have to use @{ML \||>>\} in order to account for the result(s) obtained by previous calls. A more realistic example for this combinator is the following code @@ -640,20 +640,20 @@ the theorem corresponding to the definitions. For example for the first definition: @{ML_matchresult_fake [display, gray] - "let + \let val (one_trm, (_, one_thm)) = one_def in pwriteln (pretty_term ctxt' one_trm); pwriteln (pretty_thm ctxt' one_thm) -end" - "One -One \ 1"} - Recall that @{ML "|>"} is the reverse function application. Recall also that - the related reverse function composition is @{ML "#>"}. In fact all the - combinators @{ML "|->"}, @{ML "|>>"} , @{ML "||>"} and @{ML "||>>"} +end\ + \One +One \ 1\} + Recall that @{ML \|>\} is the reverse function application. Recall also that + the related reverse function composition is @{ML \#>\}. In fact all the + combinators @{ML \|->\}, @{ML \|>>\} , @{ML \||>\} and @{ML \||>>\} described above have related combinators for function composition, namely @{ML_ind "#->" in Basics}, @{ML_ind "#>>" in Basics}, @{ML_ind "##>" in - Basics} and @{ML_ind "##>>" in Basics}. Using @{ML "#->"}, for example, the + Basics} and @{ML_ind "##>>" in Basics}. Using @{ML \#->\}, for example, the function \double\ can also be written as: \ @@ -667,22 +667,22 @@ sometimes necessary to do some ``plumbing'' in order to fit functions together. We have already seen such plumbing in the function @{ML apply_fresh_args}, where @{ML curry} is needed for making the function @{ML - list_comb}, which works over pairs, to fit with the combinator @{ML "|>"}. Such + list_comb}, which works over pairs, to fit with the combinator @{ML \|>\}. Such plumbing is also needed in situations where a function operates over lists, but one calculates only with a single element. An example is the function @{ML_ind check_terms in Syntax}, whose purpose is to simultaneously type-check a list of terms. Consider the code: @{ML_matchresult_fake [display, gray] - "let + \let val ctxt = @{context} in - map (Syntax.parse_term ctxt) [\"m + n\", \"m * n\", \"m - (n::nat)\"] + map (Syntax.parse_term ctxt) ["m + n", "m * n", "m - (n::nat)"] |> Syntax.check_terms ctxt |> pretty_terms ctxt |> pwriteln -end" - "m + n, m * n, m - n"} +end\ + \m + n, m * n, m - n\} \ text \ @@ -695,15 +695,15 @@ in terms of @{ML singleton} and @{ML check_terms in Syntax}.} For example @{ML_matchresult_fake [display, gray, linenos] - "let + \let val ctxt = @{context} in - Syntax.parse_term ctxt \"m - (n::nat)\" + Syntax.parse_term ctxt "m - (n::nat)" |> singleton (Syntax.check_terms ctxt) |> pretty_term ctxt |> pwriteln -end" - "m - n"} +end\ + \m - n\} where in Line 5, the function operating over lists fits with the single term generated in Line 4. @@ -716,7 +716,7 @@ \end{readmore} \begin{exercise} - Find out what the combinator @{ML "K I"} does. + Find out what the combinator @{ML \K I\} does. \end{exercise} \ @@ -743,7 +743,7 @@ are indicated by the @{ML_text @}-sign followed by text wrapped in \{\}\. For example, one can print out the name of the current theory with the code - @{ML_matchresult [display,gray] "Context.theory_name @{theory}" "\"First_Steps\""} + @{ML_matchresult [display,gray] \Context.theory_name @{theory}\ \"First_Steps"\} where \@{theory}\ is an antiquotation that is substituted with the current theory (remember that we assumed we are inside the theory @@ -772,34 +772,34 @@ defined abbreviations. For example @{ML_matchresult_fake [display, gray] - "Proof_Context.print_abbrevs false @{context}" -"\ + \Proof_Context.print_abbrevs false @{context}\ +\\ INTER \ INFI Inter \ Inf -\"} +\\} The precise output of course depends on the abbreviations that are currently defined; this can change over time. You can also use antiquotations to refer to proved theorems: \@{thm \}\ for a single theorem - @{ML_matchresult_fake [display,gray] "@{thm allI}" "(\x. ?P x) \ \x. ?P x"} + @{ML_matchresult_fake [display,gray] \@{thm allI}\ \(\x. ?P x) \ \x. ?P x\} and \@{thms \}\ for more than one @{ML_matchresult_fake [display,gray] - "@{thms conj_ac}" -"(?P \ ?Q) = (?Q \ ?P) + \@{thms conj_ac}\ +\(?P \ ?Q) = (?Q \ ?P) (?P \ ?Q \ ?R) = (?Q \ ?P \ ?R) -((?P \ ?Q) \ ?R) = (?P \ ?Q \ ?R)"} +((?P \ ?Q) \ ?R) = (?P \ ?Q \ ?R)\} The thm-antiquotations can also be used for manipulating theorems. For example, if you need the version of the theorem @{thm [source] refl} that has a meta-equality instead of an equality, you can write @{ML_matchresult_fake [display,gray] - "@{thm refl[THEN eq_reflection]}" - "?x \ ?x"} + \@{thm refl[THEN eq_reflection]}\ + \?x \ ?x\} The point of these antiquotations is that referring to theorems in this way makes your code independent from what theorems the user might have stored @@ -817,9 +817,9 @@ The result can be printed out as follows. @{ML_matchresult_fake [gray,display] -"foo_thms |> pretty_thms_no_vars @{context} - |> pwriteln" - "True, False \ P"} +\foo_thms |> pretty_thms_no_vars @{context} + |> pwriteln\ + \True, False \ P\} You can also refer to the current simpset via an antiquotation. To illustrate this we implement the function that extracts the theorem names stored in a @@ -841,8 +841,8 @@ The current simpset can be referred to using @{ML_ind simpset_of in Raw_Simplifier}. @{ML_matchresult_fake [display,gray] - "get_thm_names_from_ss @{context}" - "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \]"} + \get_thm_names_from_ss @{context}\ + \["Nat.of_nat_eq_id", "Int.of_int_eq_id", "Nat.One_nat_def", \]\} Again, this way of referencing simpsets makes you independent from additions of lemmas to the simpset by the user, which can potentially cause loops in your @@ -885,8 +885,8 @@ in more detail in later sections.) An example for this antiquotation is: @{ML_matchresult_fake [display,gray] - "@{term_pat \"Suc (?x::nat)\"}" - "Const (\"Suc\", \"nat \ nat\") $ Var ((\"x\", 0), \"nat\")"} + \@{term_pat "Suc (?x::nat)"}\ + \Const ("Suc", "nat \ nat") $ Var (("x", 0), "nat")\} which shows the internal representation of the term \Suc ?x\. Similarly we can write an antiquotation for type patterns. Its code is @@ -981,18 +981,18 @@ The data can be retrieved with the projection functions defined above. @{ML_matchresult_fake [display, gray] -"project_int (nth foo_list 0); -project_bool (nth foo_list 1)" -"13 -true"} +\project_int (nth foo_list 0); +project_bool (nth foo_list 1)\ +\13 +true\} Notice that we access the integer as an integer and the boolean as a boolean. If we attempt to access the integer as a boolean, then we get a runtime error. @{ML_matchresult_fake [display, gray] -"project_bool (nth foo_list 0)" -"*** exception Match raised"} +\project_bool (nth foo_list 0)\ +\*** exception Match raised\} This runtime error is the reason why ML is still type-sound despite containing a universal type. @@ -1063,8 +1063,8 @@ Section~\ref{sec:theories}). The lookup can now be performed as follows. @{ML_matchresult_fake [display, gray] -"lookup @{theory} \"conj\"" -"SOME \"\?P; ?Q\ \ ?P \ ?Q\""} +\lookup @{theory} "conj"\ +\SOME "\?P; ?Q\ \ ?P \ ?Q"\} An important point to note is that these tables (and data in general) need to be treated in a purely functional fashion. Although @@ -1077,8 +1077,8 @@ and accordingly, @{ML lookup} now produces the introduction rule for @{term "True"} @{ML_matchresult_fake [display, gray] -"lookup @{theory} \"conj\"" -"SOME \"True\""} +\lookup @{theory} "conj"\ +\SOME "True"\} there are no references involved. This is one of the most fundamental coding conventions for programming in Isabelle. References @@ -1096,11 +1096,11 @@ text \ We initialise the reference with the empty list. Consequently a first - lookup produces @{ML "ref []" in Unsynchronized}. + lookup produces @{ML \ref []\ in Unsynchronized}. @{ML_matchresult_fake [display,gray] - "WrongRefData.get @{theory}" - "ref []"} + \WrongRefData.get @{theory}\ + \ref []\} For updating the reference we use the following function \ @@ -1118,23 +1118,23 @@ text \ A lookup in the current theory gives then the expected list - @{ML "ref [1]" in Unsynchronized}. + @{ML \ref [1]\ in Unsynchronized}. @{ML_matchresult_fake [display,gray] - "WrongRefData.get @{theory}" - "ref [1]"} + \WrongRefData.get @{theory}\ + \ref [1]\} So far everything is as expected. But, the trouble starts if we attempt to backtrack to the ``point'' before the \isacommand{setup}-command. There, we would expect that the list is empty again. But since it is stored in a reference, Isabelle has no control over it. So it is not empty, but still - @{ML "ref [1]" in Unsynchronized}. Adding to the trouble, if we execute the - \isacommand{setup}-command again, we do not obtain @{ML "ref [1]" in + @{ML \ref [1]\ in Unsynchronized}. Adding to the trouble, if we execute the + \isacommand{setup}-command again, we do not obtain @{ML \ref [1]\ in Unsynchronized}, but @{ML_matchresult_fake [display,gray] - "WrongRefData.get @{theory}" - "ref [1, 1]"} + \WrongRefData.get @{theory}\ + \ref [1, 1]\} Now imagine how often you go backwards and forwards in your proof scripts.\footnote{The same problem can be triggered in the Jedit GUI by @@ -1180,22 +1180,22 @@ \@{context}\ and update it in various ways. @{ML_matchresult_fake [display,gray] -"let +\let val ctxt0 = @{context} - val ctxt1 = ctxt0 |> update @{term \"False\"} - |> update @{term \"True \ True\"} - val ctxt2 = ctxt0 |> update @{term \"1::nat\"} - val ctxt3 = ctxt2 |> update @{term \"2::nat\"} + val ctxt1 = ctxt0 |> update @{term "False"} + |> update @{term "True \ True"} + val ctxt2 = ctxt0 |> update @{term "1::nat"} + val ctxt3 = ctxt2 |> update @{term "2::nat"} in print ctxt0; print ctxt1; print ctxt2; print ctxt3 -end" -"Empty! +end\ +\Empty! True \ True, False 1 -2, 1"} +2, 1\} Many functions in Isabelle manage and update data in a similar fashion. Consequently, such calculations with contexts occur frequently in @@ -1272,8 +1272,8 @@ @{ML FooRules.get}: @{ML_matchresult_fake [display,gray] - "FooRules.get @{context}" - "[\"True\", \"?C\",\"?B\"]"} + \FooRules.get @{context}\ + \["True", "?C","?B"]\} Note that this function takes a proof context as argument. This might be confusing, since the theorem list is stored as theory data. It becomes clear by knowing @@ -1309,30 +1309,30 @@ function @{ML_ind get in Config} from a proof context @{ML_matchresult [display,gray] - "Config.get @{context} bval" - "true"} + \Config.get @{context} bval\ + \true\} or directly from a theory using the function @{ML_ind get_global in Config} @{ML_matchresult [display,gray] - "Config.get_global @{theory} bval" - "true"} + \Config.get_global @{theory} bval\ + \true\} It is also possible to manipulate the configuration values from the ML-level with the functions @{ML_ind put in Config} and @{ML_ind put_global in Config}. For example @{ML_matchresult [display,gray] - "let + \let val ctxt = @{context} - val ctxt' = Config.put sval \"foo\" ctxt - val ctxt'' = Config.put sval \"bar\" ctxt' + val ctxt' = Config.put sval "foo" ctxt + val ctxt'' = Config.put sval "bar" ctxt' in (Config.get ctxt sval, Config.get ctxt' sval, Config.get ctxt'' sval) -end" - "(\"some string\", \"foo\", \"bar\")"} +end\ + \("some string", "foo", "bar")\} A concrete example for a configuration value is @{ML_ind simp_trace in Raw_Simplifier}, which switches on trace information