ProgTutorial/FirstSteps.thy
changeset 310 007922777ff1
parent 309 ed797395fab6
child 311 ee864694315b
equal deleted inserted replaced
309:ed797395fab6 310:007922777ff1
     1 theory FirstSteps
     1 theory FirstSteps
     2 imports Base
     2 imports Base
       
     3 uses "FirstSteps.ML"
     3 begin
     4 begin
       
     5 
       
     6 
     4 
     7 
     5 chapter {* First Steps *}
     8 chapter {* First Steps *}
     6 
     9 
     7 text {*
    10 text {*
     8   Isabelle programming is done in ML. Just like lemmas and proofs, ML-code
    11   Isabelle programming is done in ML. Just like lemmas and proofs, ML-code
   163   @{ML [display,gray] "redirect_tracing (TextIO.openOut \"foo.bar\")"}
   166   @{ML [display,gray] "redirect_tracing (TextIO.openOut \"foo.bar\")"}
   164 
   167 
   165   will cause that all tracing information is printed into the file @{text "foo.bar"}.
   168   will cause that all tracing information is printed into the file @{text "foo.bar"}.
   166 
   169 
   167   You can print out error messages with the function @{ML [index] error}; for 
   170   You can print out error messages with the function @{ML [index] error}; for 
   168   example:\footnote{FIXME: unwanted pagebreak}
   171   example:
   169 
   172 
   170 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" 
   173 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" 
   171 "Exception- ERROR \"foo\" raised
   174 "Exception- ERROR \"foo\" raised
   172 At command \"ML\"."}
   175 At command \"ML\"."}
   173 
   176 
   192 
   195 
   193 ML {* Toplevel.program (fn () => innocent ()) *}
   196 ML {* Toplevel.program (fn () => innocent ()) *}
   194 *)
   197 *)
   195 
   198 
   196 text {*
   199 text {*
   197   Most often you want to inspect data of Isabelle's most basic datastructures,
   200   Most often you want to inspect data of Isabelle's most basic data
   198   namely @{ML_type term}, @{ML_type cterm} or @{ML_type thm}. Isabelle
   201   structures, namely @{ML_type term}, @{ML_type cterm} or @{ML_type
   199   contains elaborate pretty-printing functions for printing them (see Section
   202   thm}. Isabelle contains elaborate pretty-printing functions for printing
   200   \ref{sec:pretty}), but for quick-and-dirty solutions they are far too
   203   them (see Section \ref{sec:pretty}), but for quick-and-dirty solutions they
   201   unwieldy. One way to transform a term into a string is to use the function
   204   are a bit unwieldy. One way to transform a term into a string is to use the
   202   @{ML [index] string_of_term in Syntax}.
   205   function @{ML [index] string_of_term in Syntax} in structure @{ML_struct
   203 
   206   Syntax}, which we bind for more convenience to the toplevel.
       
   207 *}
       
   208 
       
   209 ML{*val string_of_term = Syntax.string_of_term*}
       
   210 
       
   211 text {*
       
   212   It can now be used as follows
   204 
   213 
   205   @{ML_response_fake [display,gray]
   214   @{ML_response_fake [display,gray]
   206   "Syntax.string_of_term @{context} @{term \"1::nat\"}"
   215   "string_of_term @{context} @{term \"1::nat\"}"
   207   "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""}
   216   "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""}
   208 
   217 
   209   This produces a string with some additional information encoded in it. The string
   218   This produces a string corrsponding to the term @{term [show_types] "1::nat"} with some
   210   can be properly printed by using either the function @{ML [index] writeln} or 
   219   additional information encoded in it. The string can be properly printed by
   211   @{ML [index] tracing}:
   220   using either the function @{ML [index] writeln} or @{ML [index] tracing}:
   212 
   221 
   213   @{ML_response_fake [display,gray]
   222   @{ML_response_fake [display,gray]
   214   "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})"
   223   "writeln (string_of_term @{context} @{term \"1::nat\"})"
   215   "\"1\""}
   224   "\"1\""}
   216 
   225 
   217   or
   226   or
   218 
   227 
   219   @{ML_response_fake [display,gray]
   228   @{ML_response_fake [display,gray]
   220   "tracing (Syntax.string_of_term @{context} @{term \"1::nat\"})"
   229   "tracing (string_of_term @{context} @{term \"1::nat\"})"
   221   "\"1\""}
   230   "\"1\""}
   222 
   231 
       
   232   If there are more than one @{ML_type term}s to be printed, you can use the 
       
   233   function @{ML [index] commas} to separate them.
       
   234 *} 
       
   235 
       
   236 ML{*fun string_of_terms ctxt ts =  
       
   237   commas (map (string_of_term ctxt) ts)*}
       
   238 
       
   239 text {*
   223   A @{ML_type cterm} can be transformed into a string by the following function.
   240   A @{ML_type cterm} can be transformed into a string by the following function.
   224 *}
   241 *}
   225 
   242 
   226 ML{*fun string_of_cterm ctxt t =  
   243 ML{*fun string_of_cterm ctxt t =  
   227   Syntax.string_of_term ctxt (term_of t)*}
   244   string_of_term ctxt (term_of t)*}
   228 
   245 
   229 text {*
   246 text {*
   230   In this example the function @{ML [index] term_of} extracts the @{ML_type term} from
   247   In this example the function @{ML [index] term_of} extracts the @{ML_type term} from
   231   a @{ML_type cterm}.  If there are more than one @{ML_type cterm}s to be
   248   a @{ML_type cterm}.  More than one @{ML_type cterm}s can again be printed
   232   printed, you can use the function @{ML [index] commas} to separate them.
   249   with @{ML [index] commas}.
   233 *} 
   250 *} 
   234 
   251 
   235 ML{*fun string_of_cterms ctxt ts =  
   252 ML{*fun string_of_cterms ctxt cts =  
   236   commas (map (string_of_cterm ctxt) ts)*}
   253   commas (map (string_of_cterm ctxt) cts)*}
   237 
   254 
   238 text {*
   255 text {*
   239   The easiest way to get the string of a theorem is to transform it
   256   The easiest way to get the string of a theorem is to transform it
   240   into a @{ML_type cterm} using the function @{ML [index] crep_thm}. 
   257   into a @{ML_type cterm} using the function @{ML [index] crep_thm}. 
   241 *}
   258 *}
   249 
   266 
   250   @{ML_response_fake [display, gray]
   267   @{ML_response_fake [display, gray]
   251   "tracing (string_of_thm @{context} @{thm conjI})"
   268   "tracing (string_of_thm @{context} @{thm conjI})"
   252   "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"}
   269   "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"}
   253 
   270 
   254   In order to improve the readability of theorems we convert
   271   In order to improve the readability of theorems we convert these schematic
   255   these schematic variables into free variables using the 
   272   variables into free variables using the function @{ML [index] import in
   256   function @{ML [index] import in Variable}. This is similar
   273   Variable}. This is similar to the theorem attribute @{text "[no_vars]"} from
   257   to the attribute @{text "[no_vars]"} from Isabelle's user-level.
   274   Isabelle's user-level.
   258 *}
   275 *}
   259 
   276 
   260 ML{*fun no_vars ctxt thm =
   277 ML{*fun no_vars ctxt thm =
   261 let 
   278 let 
   262   val ((_, [thm']), _) = Variable.import true [thm] ctxt
   279   val ((_, [thm']), _) = Variable.import true [thm] ctxt
   407 "let
   424 "let
   408   val t = @{term \"P::nat \<Rightarrow> int \<Rightarrow> unit \<Rightarrow> bool\"}
   425   val t = @{term \"P::nat \<Rightarrow> int \<Rightarrow> unit \<Rightarrow> bool\"}
   409   val ctxt = @{context}
   426   val ctxt = @{context}
   410 in 
   427 in 
   411   apply_fresh_args t ctxt
   428   apply_fresh_args t ctxt
   412    |> Syntax.string_of_term ctxt
   429    |> string_of_term ctxt
   413    |> tracing
   430    |> tracing
   414 end" 
   431 end" 
   415   "P z za zb"}
   432   "P z za zb"}
   416 
   433 
   417   You can read off this behaviour from how @{ML apply_fresh_args} is
   434   You can read off this behaviour from how @{ML apply_fresh_args} is
   432 "let
   449 "let
   433   val t = @{term \"za::'a \<Rightarrow> 'b \<Rightarrow> 'c\"}
   450   val t = @{term \"za::'a \<Rightarrow> 'b \<Rightarrow> 'c\"}
   434   val ctxt = @{context}
   451   val ctxt = @{context}
   435 in
   452 in
   436   apply_fresh_args t ctxt 
   453   apply_fresh_args t ctxt 
   437    |> Syntax.string_of_term ctxt
   454    |> string_of_term ctxt
   438    |> tracing
   455    |> tracing
   439 end"
   456 end"
   440   "za z zb"}
   457   "za z zb"}
   441   
   458   
   442   where the @{text "za"} is correctly avoided.
   459   where the @{text "za"} is correctly avoided.
   597 
   614 
   598 ML{*val double =
   615 ML{*val double =
   599             (fn x => (x, x))
   616             (fn x => (x, x))
   600         #-> (fn x => fn y => x + y)*}
   617         #-> (fn x => fn y => x + y)*}
   601 
   618 
   602 text {*
   619 
   603   
   620 text {* 
   604   (FIXME: find a good exercise for combinators)
   621   When using combinators for writing function in waterfall fashion, it is
   605 
   622   sometimes necessary to do some ``plumbing'' for fitting functions
       
   623   together. We have already seen such plumbing in the function @{ML
       
   624   apply_fresh_args}, where @{ML curry} is needed for making the function @{ML
       
   625   list_comb} that works over pairs to fit with the combinator @{ML "|>"}. Such 
       
   626   plumbing is also needed in situations where a functions operate over lists, 
       
   627   but one calculates only with a single entity. An example is the function 
       
   628   @{ML [index] check_terms in Syntax}, whose purpose is to type-check a list 
       
   629   of terms.
       
   630 
       
   631   @{ML_response_fake [display, gray]
       
   632   "let
       
   633   val ctxt = @{context}
       
   634 in
       
   635   map (Syntax.parse_term ctxt) [\"m + n\", \"m - (n::nat)\"] 
       
   636   |> Syntax.check_terms ctxt
       
   637   |> string_of_terms ctxt
       
   638   |> tracing
       
   639 end"
       
   640   "m + n, m - n"}
       
   641 *}
       
   642 
       
   643 text {*
       
   644   In this example we obtain two terms with appropriate typing. However, if you
       
   645   have only a single term, then @{ML check_terms in Syntax} needs to be
       
   646   adapted. This can be done with the ``plumbing'' function @{ML
       
   647   singleton}.\footnote{There is in fact alread a function @{ML check_term in Syntax},
       
   648   which however is defined in terms of @{ML singleton} and @{ML check_terms in
       
   649   Syntax}.} For example
       
   650 
       
   651   @{ML_response_fake [display, gray]
       
   652   "let 
       
   653   val ctxt = @{context}
       
   654 in
       
   655   Syntax.parse_term ctxt \"m - (n::nat)\" 
       
   656   |> singleton (Syntax.check_terms ctxt)
       
   657   |> string_of_term ctxt
       
   658   |> tracing
       
   659 end"
       
   660   "m - n"}
       
   661    
   606   \begin{readmore}
   662   \begin{readmore}
   607   The most frequently used combinators are defined in the files @{ML_file
   663   The most frequently used combinators are defined in the files @{ML_file
   608   "Pure/library.ML"}
   664   "Pure/library.ML"}
   609   and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} 
   665   and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} 
   610   contains further information about combinators.
   666   contains further information about combinators.
   611   \end{readmore}
   667   \end{readmore}
   612  
   668 
   613   (FIXME: say something about calling conventions)
   669   (FIXME: find a good exercise for combinators)
   614  
   670 
   615   (FIXME: say something about singleton)
   671   (FIXME: say something about calling conventions) 
   616 *}
   672 *}
   617 
   673 
   618 
   674 
   619 section {* Antiquotations *}
   675 section {* Antiquotations *}
   620 
   676 
   829 "let
   885 "let
   830   val v1 = Var ((\"x\", 3), @{typ bool})
   886   val v1 = Var ((\"x\", 3), @{typ bool})
   831   val v2 = Var ((\"x1\", 3), @{typ bool})
   887   val v2 = Var ((\"x1\", 3), @{typ bool})
   832   val v3 = Free (\"x\", @{typ bool})
   888   val v3 = Free (\"x\", @{typ bool})
   833 in
   889 in
   834   map (Syntax.string_of_term @{context}) [v1, v2, v3]
   890   string_of_terms @{context} [v1, v2, v3]
   835   |> cat_lines
       
   836   |> tracing
   891   |> tracing
   837 end"
   892 end"
   838 "?x3
   893 "?x3, ?x1.3, x"}
   839 ?x1.3
       
   840 x"}
       
   841 
   894 
   842   When constructing terms, you are usually concerned with free variables (as mentioned earlier,
   895   When constructing terms, you are usually concerned with free variables (as mentioned earlier,
   843   you cannot construct schematic variables using the antiquotation @{text "@{term \<dots>}"}). 
   896   you cannot construct schematic variables using the antiquotation @{text "@{term \<dots>}"}). 
   844   If you deal with theorems, you have to, however, observe the distinction. A similar
   897   If you deal with theorems, you have to, however, observe the distinction. A similar
   845   distinction holds for types (see below).
   898   distinction holds for types (see below).
   862 
   915 
   863   @{ML_response_fake [display,gray] 
   916   @{ML_response_fake [display,gray] 
   864 "let
   917 "let
   865   val omega = Free (\"x\", @{typ nat}) $ Free (\"x\", @{typ nat})
   918   val omega = Free (\"x\", @{typ nat}) $ Free (\"x\", @{typ nat})
   866 in 
   919 in 
   867   tracing (Syntax.string_of_term @{context} omega)
   920   tracing (string_of_term @{context} omega)
   868 end"
   921 end"
   869   "x x"}
   922   "x x"}
   870 
   923 
   871   with the raw ML-constructors.
   924   with the raw ML-constructors.
   872   
   925   
  1083   @{ML_response_fake [display, gray, linenos]
  1136   @{ML_response_fake [display, gray, linenos]
  1084   "let
  1137   "let
  1085   val (vrs, trm) = strip_alls @{term \"\<forall>x y. x = (y::bool)\"}
  1138   val (vrs, trm) = strip_alls @{term \"\<forall>x y. x = (y::bool)\"}
  1086 in 
  1139 in 
  1087   subst_bounds (rev vrs, trm) 
  1140   subst_bounds (rev vrs, trm) 
  1088   |> Syntax.string_of_term @{context}
  1141   |> string_of_term @{context}
  1089   |> tracing
  1142   |> tracing
  1090 end"
  1143 end"
  1091   "x = y"}
  1144   "x = y"}
  1092 
  1145 
  1093   Note that in Line 4 we had to reverse the list of variables that @{ML strip_alls}
  1146   Note that in Line 4 we had to reverse the list of variables that @{ML strip_alls}
  1102 
  1155 
  1103 @{ML_response_fake [gray,display]
  1156 @{ML_response_fake [gray,display]
  1104 "let
  1157 "let
  1105   val eq = HOLogic.mk_eq (@{term \"True\"}, @{term \"False\"})
  1158   val eq = HOLogic.mk_eq (@{term \"True\"}, @{term \"False\"})
  1106 in
  1159 in
  1107   tracing (Syntax.string_of_term @{context} eq)
  1160   tracing (string_of_term @{context} eq)
  1108 end"
  1161 end"
  1109   "True = False"}
  1162   "True = False"}
  1110 *}
  1163 *}
  1111 
  1164 
  1112 text {*
  1165 text {*
  1514   let val prems = Logic.strip_imp_prems t in
  1567   let val prems = Logic.strip_imp_prems t in
  1515     if i <= length prems
  1568     if i <= length prems
  1516     then let val (params,t) = strip_assums_all([], nth prems (i - 1))
  1569     then let val (params,t) = strip_assums_all([], nth prems (i - 1))
  1517          in subst_bounds(map Free params, t) end
  1570          in subst_bounds(map Free params, t) end
  1518     else error ("Not enough premises for prem" ^ string_of_int i ^
  1571     else error ("Not enough premises for prem" ^ string_of_int i ^
  1519       " in propositon: " ^ Syntax.string_of_term ctxt t)
  1572       " in propositon: " ^ string_of_term ctxt t)
  1520   end;
  1573   end;
  1521 *}
  1574 *}
  1522 
  1575 
  1523 ML {*
  1576 ML {*
  1524 strip_assums_all ([], @{term "\<And>x y. A x y"})
  1577 strip_assums_all ([], @{term "\<And>x y. A x y"})