spilt the Essential's chapter
authorChristian Urban <urbanc@in.tum.de>
Thu, 19 Nov 2009 17:48:44 +0100
changeset 395 2c392f61f400
parent 394 0019ebf76e10
child 396 a2e49e0771b3
spilt the Essential's chapter
ProgTutorial/Advanced.thy
ProgTutorial/Essential.thy
ProgTutorial/General.thy
ProgTutorial/ROOT.ML
progtutorial.pdf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProgTutorial/Advanced.thy	Thu Nov 19 17:48:44 2009 +0100
@@ -0,0 +1,236 @@
+theory Advanced
+imports Base FirstSteps
+begin
+
+(*<*)
+setup{*
+open_file_with_prelude 
+  "Advanced_Code.thy"
+  ["theory General", "imports Base FirstSteps", "begin"]
+*}
+(*>*)
+
+
+chapter {* Advanced Isabelle *}
+
+text {*
+  TBD
+*}
+
+section {* Theories\label{sec:theories} (TBD) *}
+
+text {*
+  Theories are the most fundamental building blocks in Isabelle. They 
+  contain definitions, syntax declarations, axioms, proofs etc. If a definition
+  is stated, it must be stored in a theory in order to be usable later
+  on. Similar with proofs: once a proof is finished, the proved theorem
+  needs to be stored in the theorem database of the theory in order to
+  be usable. All relevant data of a theort can be querried as follows.
+
+  \begin{isabelle}
+  \isacommand{print\_theory}\\
+  @{text "> names: Pure Code_Generator HOL \<dots>"}\\
+  @{text "> classes: Inf < type \<dots>"}\\
+  @{text "> default sort: type"}\\
+  @{text "> syntactic types: #prop \<dots>"}\\
+  @{text "> logical types: 'a \<times> 'b \<dots>"}\\
+  @{text "> type arities: * :: (random, random) random \<dots>"}\\
+  @{text "> logical constants: == :: 'a \<Rightarrow> 'a \<Rightarrow> prop \<dots>"}\\
+  @{text "> abbreviations: \<dots>"}\\
+  @{text "> axioms: \<dots>"}\\
+  @{text "> oracles: \<dots>"}\\
+  @{text "> definitions: \<dots>"}\\
+  @{text "> theorems: \<dots>"}
+  \end{isabelle}
+
+  \begin{center}
+  \begin{tikzpicture}
+  \node[top color=white, bottom color=gray!30, draw=black!100, drop shadow] {A};
+  \end{tikzpicture}
+  \end{center}
+
+
+  In contrast to an ordinary theory, which simply consists of a type
+  signature, as well as tables for constants, axioms and theorems, a local
+  theory contains additional context information, such as locally fixed
+  variables and local assumptions that may be used by the package. The type
+  @{ML_type local_theory} is identical to the type of \emph{proof contexts}
+  @{ML_type "Proof.context"}, although not every proof context constitutes a
+  valid local theory.
+
+  @{ML "Context.>> o Context.map_theory"}
+
+  \footnote{\bf FIXME: list append in merge operations can cause 
+  exponential blowups.}
+*}
+
+section {* Setups (TBD) *}
+
+text {*
+  @{ML Sign.declare_const}
+
+  In the previous section we used \isacommand{setup} in order to make
+  a theorem attribute known to Isabelle. What happens behind the scenes
+  is that \isacommand{setup} expects a function of type 
+  @{ML_type "theory -> theory"}: the input theory is the current theory and the 
+  output the theory where the theory attribute has been stored.
+  
+  This is a fundamental principle in Isabelle. A similar situation occurs 
+  for example with declaring constants. The function that declares a 
+  constant on the ML-level is @{ML_ind  add_consts_i in Sign}. 
+  If you write\footnote{Recall that ML-code  needs to be 
+  enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} 
+*}  
+
+ML{*Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] @{theory} *}
+
+text {*
+  for declaring the constant @{text "BAR"} with type @{typ nat} and 
+  run the code, then you indeed obtain a theory as result. But if you 
+  query the constant on the Isabelle level using the command \isacommand{term}
+
+  \begin{isabelle}
+  \isacommand{term}~@{text [quotes] "BAR"}\\
+  @{text "> \"BAR\" :: \"'a\""}
+  \end{isabelle}
+
+  you do not obtain a constant of type @{typ nat}, but a free variable (printed in 
+  blue) of polymorphic type. The problem is that the ML-expression above did 
+  not register the declaration with the current theory. This is what the command
+  \isacommand{setup} is for. The constant is properly declared with
+*}
+
+setup %gray {* Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] *}
+
+text {* 
+  Now 
+  
+  \begin{isabelle}
+  \isacommand{term}~@{text [quotes] "BAR"}\\
+  @{text "> \"BAR\" :: \"nat\""}
+  \end{isabelle}
+
+  returns a (black) constant with the type @{typ nat}.
+
+  A similar command is \isacommand{local\_setup}, which expects a function
+  of type @{ML_type "local_theory -> local_theory"}. Later on we will also
+  use the commands \isacommand{method\_setup} for installing methods in the
+  current theory and \isacommand{simproc\_setup} for adding new simprocs to
+  the current simpset.
+*}
+
+section {* Contexts (TBD) *}
+
+section {* Local Theories (TBD) *}
+
+text {*
+  @{ML_ind "Local_Theory.declaration"}
+*}
+
+(*
+setup {*
+ Sign.add_consts_i [(Binding"bar", @{typ "nat"},NoSyn)] 
+*}
+lemma "bar = (1::nat)"
+  oops
+
+setup {*   
+  Sign.add_consts_i [("foo", @{typ "nat"},NoSyn)] 
+ #> PureThy.add_defs false [((@{binding "foo_def"}, 
+       Logic.mk_equals (Const ("FirstSteps.foo", @{typ "nat"}), @{term "1::nat"})), [])] 
+ #> snd
+*}
+*)
+(*
+lemma "foo = (1::nat)"
+  apply(simp add: foo_def)
+  done
+
+thm foo_def
+*)
+
+section {* Morphisms (TBD) *}
+
+text {*
+  Morphisms are arbitrary transformations over terms, types, theorems and bindings.
+  They can be constructed using the function @{ML_ind morphism in Morphism},
+  which expects a record with functions of type
+
+  \begin{isabelle}
+  \begin{tabular}{rl}
+  @{text "binding:"} & @{text "binding -> binding"}\\
+  @{text "typ:"}     & @{text "typ -> typ"}\\
+  @{text "term:"}    & @{text "term -> term"}\\
+  @{text "fact:"}    & @{text "thm list -> thm list"}
+  \end{tabular}
+  \end{isabelle}
+
+  The simplest morphism is the  @{ML_ind identity in Morphism}-morphism defined as
+*}
+
+ML{*val identity = Morphism.morphism {binding = I, typ = I, term = I, fact = I}*}
+  
+text {*
+  Morphisms can be composed with the function @{ML_ind "$>" in Morphism}
+*}
+
+ML{*fun trm_phi (Free (x, T)) = Var ((x, 0), T) 
+  | trm_phi (Abs (x, T, t)) = Abs (x, T, trm_phi t)
+  | trm_phi (t $ s) = (trm_phi t) $ (trm_phi s)
+  | trm_phi t = t*}
+
+ML{*val phi = Morphism.term_morphism trm_phi*}
+
+ML{*Morphism.term phi @{term "P x y"}*}
+
+text {*
+  @{ML_ind term_morphism in Morphism}
+
+  @{ML_ind term in Morphism},
+  @{ML_ind thm in Morphism}
+
+  \begin{readmore}
+  Morphisms are implemented in the file @{ML_file "Pure/morphism.ML"}.
+  \end{readmore}
+*}
+
+section {* Misc (TBD) *}
+
+ML {*Datatype.get_info @{theory} "List.list"*}
+
+text {* 
+FIXME: association lists:
+@{ML_file "Pure/General/alist.ML"}
+
+FIXME: calling the ML-compiler
+
+*}
+
+section {* Managing Name Spaces (TBD) *}
+
+ML {* Sign.intern_type @{theory} "list" *}
+ML {* Sign.intern_const @{theory} "prod_fun" *}
+
+
+text {* 
+  @{ML_ind "Binding.str_of"} returns the string with markup;
+  @{ML_ind "Binding.name_of"} returns the string without markup
+
+  @{ML_ind "Binding.conceal"} 
+*}
+
+section {* Concurrency (TBD) *}
+
+text {*
+  @{ML_ind prove_future in Goal}
+  @{ML_ind future_result in Goal}
+  @{ML_ind fork_pri in Future}
+*}
+
+section {* Summary *}
+
+text {*
+  TBD
+*}
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProgTutorial/Essential.thy	Thu Nov 19 17:48:44 2009 +0100
@@ -0,0 +1,2359 @@
+theory Essential
+imports Base FirstSteps
+begin
+
+(*<*)
+setup{*
+open_file_with_prelude 
+  "Esseantial_Code.thy"
+  ["theory General", "imports Base FirstSteps", "begin"]
+*}
+(*>*)
+
+
+chapter {* Isabelle Essentials *}
+
+text {*
+  Isabelle is build around a few central ideas. One central idea is the
+  LCF-approach to theorem proving where there is a small trusted core and
+  everything else is build on top of this trusted core 
+  \cite{GordonMilnerWadsworth79}. The fundamental data
+  structures involved in this core are certified terms and certified types, 
+  as well as theorems.
+*}
+
+
+section {* Terms and Types *}
+
+text {*
+  In Isabelle, there are certified terms and uncertified terms (respectively types). 
+  Uncertified terms are often just called terms. One way to construct them is by 
+  using the antiquotation \mbox{@{text "@{term \<dots>}"}}. For example
+
+  @{ML_response [display,gray] 
+"@{term \"(a::nat) + b = c\"}" 
+"Const (\"op =\", \<dots>) $ 
+  (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
+
+  constructs the term @{term "(a::nat) + b = c"}. The resulting term is printed using 
+  the internal representation corresponding to the datatype @{ML_type_ind "term"}, 
+  which is defined as follows: 
+*}  
+
+ML_val %linenosgray{*datatype term =
+  Const of string * typ 
+| Free of string * typ 
+| Var of indexname * typ 
+| Bound of int 
+| Abs of string * typ * term 
+| $ of term * term *}
+
+text {*
+  This datatype implements Church-style lambda-terms, where types are
+  explicitly recorded in variables, constants and abstractions.  As can be
+  seen in Line 5, terms use the usual de Bruijn index mechanism for
+  representing bound variables.  For example in
+
+  @{ML_response_fake [display, gray]
+  "@{term \"\<lambda>x y. x y\"}"
+  "Abs (\"x\", \"'a \<Rightarrow> 'b\", Abs (\"y\", \"'a\", Bound 1 $ Bound 0))"}
+
+  the indices refer to the number of Abstractions (@{ML Abs}) that we need to
+  skip until we hit the @{ML Abs} that binds the corresponding
+  variable. Constructing a term with dangling de Bruijn indices is possible,
+  but will be flagged as ill-formed when you try to typecheck or certify it
+  (see Section~\ref{sec:typechecking}). Note that the names of bound variables
+  are kept at abstractions for printing purposes, and so should be treated
+  only as ``comments''.  Application in Isabelle is realised with the
+  term-constructor @{ML $}.
+
+  Isabelle makes a distinction between \emph{free} variables (term-constructor
+  @{ML Free} and written on the user level in blue colour) and
+  \emph{schematic} variables (term-constructor @{ML Var} and written with a
+  leading question mark). Consider the following two examples
+  
+  @{ML_response_fake [display, gray]
+"let
+  val v1 = Var ((\"x\", 3), @{typ bool})
+  val v2 = Var ((\"x1\", 3), @{typ bool})
+  val v3 = Free (\"x\", @{typ bool})
+in
+  string_of_terms @{context} [v1, v2, v3]
+  |> tracing
+end"
+"?x3, ?x1.3, x"}
+
+  When constructing terms, you are usually concerned with free variables (as
+  mentioned earlier, you cannot construct schematic variables using the
+  antiquotation @{text "@{term \<dots>}"}). If you deal with theorems, you have to,
+  however, observe the distinction. The reason is that only schematic
+  variables can be instantiated with terms when a theorem is applied. A
+  similar distinction between free and schematic variables holds for types
+  (see below).
+
+  \begin{readmore}
+  Terms and types are described in detail in \isccite{sec:terms}. Their
+  definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}.
+  For constructing terms involving HOL constants, many helper functions are defined
+  in @{ML_file "HOL/Tools/hologic.ML"}.
+  \end{readmore}
+  
+  Constructing terms via antiquotations has the advantage that only typable
+  terms can be constructed. For example
+
+  @{ML_response_fake_both [display,gray]
+  "@{term \"x x\"}"
+  "Type unification failed: Occurs check!"}
+
+  raises a typing error, while it perfectly ok to construct the term
+
+  @{ML_response_fake [display,gray] 
+"let
+  val omega = Free (\"x\", @{typ \"nat \<Rightarrow> nat\"}) $ Free (\"x\", @{typ nat})
+in 
+  tracing (string_of_term @{context} omega)
+end"
+  "x x"}
+
+  with the raw ML-constructors.
+  
+  Sometimes the internal representation of terms can be surprisingly different
+  from what you see at the user-level, because the layers of
+  parsing/type-checking/pretty printing can be quite elaborate. 
+
+  \begin{exercise}
+  Look at the internal term representation of the following terms, and
+  find out why they are represented like this:
+
+  \begin{itemize}
+  \item @{term "case x of 0 \<Rightarrow> 0 | Suc y \<Rightarrow> y"}  
+  \item @{term "\<lambda>(x,y). P y x"}  
+  \item @{term "{ [x::int] | x. x \<le> -2 }"}  
+  \end{itemize}
+
+  Hint: The third term is already quite big, and the pretty printer
+  may omit parts of it by default. If you want to see all of it, you
+  can use the following ML-function to set the printing depth to a higher 
+  value:
+
+  @{ML [display,gray] "print_depth 50"}
+  \end{exercise}
+
+  The antiquotation @{text "@{prop \<dots>}"} constructs terms by inserting the 
+  usually invisible @{text "Trueprop"}-coercions whenever necessary. 
+  Consider for example the pairs
+
+@{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" 
+"(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>),
+ Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"}
+ 
+  where a coercion is inserted in the second component and 
+
+  @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" 
+  "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, 
+ Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"}
+
+  where it is not (since it is already constructed by a meta-implication). 
+  The purpose of the @{text "Trueprop"}-coercion is to embed formulae of
+  an object logic, for example HOL, into the meta-logic of Isabelle. The coercion
+  is needed whenever a term is constructed that will be proved as a theorem. 
+
+  As already seen above, types can be constructed using the antiquotation 
+  @{text "@{typ \<dots>}"}. For example:
+
+  @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"}
+
+  The corresponding datatype is
+*}
+  
+ML_val{*datatype typ =
+  Type  of string * typ list 
+| TFree of string * sort 
+| TVar  of indexname * sort *}
+
+text {*
+  Like with terms, there is the distinction between free type
+  variables (term-constructor @{ML "TFree"}) and schematic
+  type variables (term-constructor @{ML "TVar"} and printed with
+  a leading question mark). A type constant,
+  like @{typ "int"} or @{typ bool}, are types with an empty list
+  of argument types. However, it needs a bit of effort to show an
+  example, because Isabelle always pretty prints types (unlike terms).
+  Using just the antiquotation @{text "@{typ \"bool\"}"} we only see
+
+  @{ML_response [display, gray]
+  "@{typ \"bool\"}"
+  "bool"}
+
+  that is the pretty printed version of @{text "bool"}. However, in PolyML
+  (version 5.3) it is easy to install your own pretty printer. With the
+  function below we mimic the behaviour of the usual pretty printer for
+  datatypes (it uses pretty-printing functions which will be explained in more
+  detail in Section~\ref{sec:pretty}).
+*}
+
+ML{*local
+  fun pp_pair (x, y) = Pretty.list "(" ")" [x, y]
+  fun pp_list xs = Pretty.list "[" "]" xs
+  fun pp_str s   = Pretty.str s
+  fun pp_qstr s  = Pretty.quote (pp_str s)
+  fun pp_int i   = pp_str (string_of_int i)
+  fun pp_sort S  = pp_list (map pp_qstr S)
+  fun pp_constr a args = Pretty.block [pp_str a, Pretty.brk 1, args]
+in
+fun raw_pp_typ (TVar ((a, i), S)) = 
+      pp_constr "TVar" (pp_pair (pp_pair (pp_qstr a, pp_int i), pp_sort S))
+  | raw_pp_typ (TFree (a, S)) = 
+      pp_constr "TFree" (pp_pair (pp_qstr a, pp_sort S))
+  | raw_pp_typ (Type (a, tys)) = 
+      pp_constr "Type" (pp_pair (pp_qstr a, pp_list (map raw_pp_typ tys)))
+end*}
+
+text {*
+  We can install this pretty printer with the function 
+  @{ML_ind addPrettyPrinter in PolyML} as follows.
+*}
+
+ML{*PolyML.addPrettyPrinter 
+  (fn _ => fn _ => ml_pretty o Pretty.to_ML o raw_pp_typ)*}
+
+text {*
+  Now the type bool is printed out in full detail.
+
+  @{ML_response [display,gray]
+  "@{typ \"bool\"}"
+  "Type (\"bool\", [])"}
+
+  When printing out a list-type
+  
+  @{ML_response [display,gray]
+  "@{typ \"'a list\"}"
+  "Type (\"List.list\", [TFree (\"'a\", [\"HOL.type\"])])"}
+
+  we can see the full name of the type is actually @{text "List.list"}, indicating
+  that it is defined in the theory @{text "List"}. However, one has to be 
+  careful with names of types, because even if
+  @{text "fun"}, @{text "bool"} and @{text "nat"} are defined in the 
+  theories @{text "HOL"} and @{text "Nat"}, respectively, they are 
+  still represented by their simple name.
+
+   @{ML_response [display,gray]
+  "@{typ \"bool \<Rightarrow> nat\"}"
+  "Type (\"fun\", [Type (\"bool\", []), Type (\"nat\", [])])"}
+
+  We can restore the usual behaviour of Isabelle's pretty printer
+  with the code
+*}
+
+ML{*PolyML.addPrettyPrinter 
+  (fn _ => fn _ => ml_pretty o Pretty.to_ML o Proof_Display.pp_typ Pure.thy)*}
+
+text {*
+  After that the types for booleans, lists and so on are printed out again 
+  the standard Isabelle way.
+
+  @{ML_response_fake [display, gray]
+  "@{typ \"bool\"};
+@{typ \"'a list\"}"
+  "\"bool\"
+\"'a List.list\""}
+
+  \begin{readmore}
+  Types are described in detail in \isccite{sec:types}. Their
+  definition and many useful operations are implemented 
+  in @{ML_file "Pure/type.ML"}.
+  \end{readmore}
+*}
+
+section {* Constructing Terms and Types Manually\label{sec:terms_types_manually} *} 
+
+text {*
+  While antiquotations are very convenient for constructing terms, they can
+  only construct fixed terms (remember they are ``linked'' at compile-time).
+  However, you often need to construct terms manually. For example, a
+  function that returns the implication @{text "\<And>(x::nat). P x \<Longrightarrow> Q x"} taking
+  @{term P} and @{term Q} as arguments can only be written as:
+
+*}
+
+ML{*fun make_imp P Q =
+let
+  val x = Free ("x", @{typ nat})
+in 
+  Logic.all x (Logic.mk_implies (P $ x, Q $ x))
+end *}
+
+text {*
+  The reason is that you cannot pass the arguments @{term P} and @{term Q} 
+  into an antiquotation.\footnote{At least not at the moment.} For example 
+  the following does \emph{not} work.
+*}
+
+ML{*fun make_wrong_imp P Q = @{prop "\<And>(x::nat). P x \<Longrightarrow> Q x"} *}
+
+text {*
+  To see this, apply @{text "@{term S}"} and @{text "@{term T}"} 
+  to both functions. With @{ML make_imp} you obtain the intended term involving 
+  the given arguments
+
+  @{ML_response [display,gray] "make_imp @{term S} @{term T}" 
+"Const \<dots> $ 
+  Abs (\"x\", Type (\"nat\",[]),
+    Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"}
+
+  whereas with @{ML make_wrong_imp} you obtain a term involving the @{term "P"} 
+  and @{text "Q"} from the antiquotation.
+
+  @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T}" 
+"Const \<dots> $ 
+  Abs (\"x\", \<dots>,
+    Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ 
+                (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"}
+
+  There are a number of handy functions that are frequently used for
+  constructing terms. One is the function @{ML_ind list_comb in Term}, which
+  takes as argument a term and a list of terms, and produces as output the
+  term list applied to the term. For example
+
+
+@{ML_response_fake [display,gray]
+"let
+  val trm = @{term \"P::nat\"}
+  val args = [@{term \"True\"}, @{term \"False\"}]
+in
+  list_comb (trm, args)
+end"
+"Free (\"P\", \"nat\") $ Const (\"True\", \"bool\") $ Const (\"False\", \"bool\")"}
+
+  Another handy function is @{ML_ind lambda in Term}, which abstracts a variable 
+  in a term. For example
+
+  @{ML_response_fake [display,gray]
+"let
+  val x_nat = @{term \"x::nat\"}
+  val trm = @{term \"(P::nat \<Rightarrow> bool) x\"}
+in
+  lambda x_nat trm
+end"
+  "Abs (\"x\", \"nat\", Free (\"P\", \"bool \<Rightarrow> bool\") $ Bound 0)"}
+
+  In this example, @{ML lambda} produces a de Bruijn index (i.e.~@{ML "Bound 0"}), 
+  and an abstraction, where it also records the type of the abstracted
+  variable and for printing purposes also its name.  Note that because of the
+  typing annotation on @{text "P"}, the variable @{text "x"} in @{text "P x"}
+  is of the same type as the abstracted variable. If it is of different type,
+  as in
+
+  @{ML_response_fake [display,gray]
+"let
+  val x_int = @{term \"x::int\"}
+  val trm = @{term \"(P::nat \<Rightarrow> bool) x\"}
+in
+  lambda x_int trm
+end"
+  "Abs (\"x\", \"int\", Free (\"P\", \"nat \<Rightarrow> bool\") $ Free (\"x\", \"nat\"))"}
+
+  then the variable @{text "Free (\"x\", \"int\")"} is \emph{not} abstracted. 
+  This is a fundamental principle
+  of Church-style typing, where variables with the same name still differ, if they 
+  have different type.
+
+  There is also the function @{ML_ind subst_free in Term} with which terms can be
+  replaced by other terms. For example below, we will replace in @{term
+  "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0 x"} the subterm @{term "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0"} by
+  @{term y}, and @{term x} by @{term True}.
+
+  @{ML_response_fake [display,gray]
+"let
+  val sub1 = (@{term \"(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0\"}, @{term \"y::nat \<Rightarrow> nat\"})
+  val sub2 = (@{term \"x::nat\"}, @{term \"True\"})
+  val trm = @{term \"((f::nat \<Rightarrow> nat \<Rightarrow> nat) 0) x\"}
+in
+  subst_free [sub1, sub2] trm
+end"
+  "Free (\"y\", \"nat \<Rightarrow> nat\") $ Const (\"True\", \"bool\")"}
+
+  As can be seen, @{ML subst_free} does not take typability into account.
+  However it takes alpha-equivalence into account:
+
+  @{ML_response_fake [display, gray]
+"let
+  val sub = (@{term \"(\<lambda>y::nat. y)\"}, @{term \"x::nat\"})
+  val trm = @{term \"(\<lambda>x::nat. x)\"}
+in
+  subst_free [sub] trm
+end"
+  "Free (\"x\", \"nat\")"}
+
+  Similarly the function @{ML_ind subst_bounds in Term}, replaces lose bound 
+  variables with terms. To see how this function works, let us implement a
+  function that strips off the outermost quantifiers in a term.
+*}
+
+ML{*fun strip_alls t =
+let 
+  fun aux (x, T, t) = strip_alls t |>> cons (Free (x, T))
+in
+  case t of
+    Const ("All", _) $ Abs body => aux body
+  | _ => ([], t)
+end*}
+
+text {*
+  The function returns a pair consisting of the stripped off variables and
+  the body of the universal quantification. For example
+
+  @{ML_response_fake [display, gray]
+  "strip_alls @{term \"\<forall>x y. x = (y::bool)\"}"
+"([Free (\"x\", \"bool\"), Free (\"y\", \"bool\")],
+  Const (\"op =\", \<dots>) $ Bound 1 $ Bound 0)"}
+
+  After calling @{ML strip_alls}, you obtain a term with lose bound variables. With
+  the function @{ML subst_bounds}, you can replace these lose @{ML_ind 
+  Bound in Term}s with the stripped off variables.
+
+  @{ML_response_fake [display, gray, linenos]
+  "let
+  val (vrs, trm) = strip_alls @{term \"\<forall>x y. x = (y::bool)\"}
+in 
+  subst_bounds (rev vrs, trm) 
+  |> string_of_term @{context}
+  |> tracing
+end"
+  "x = y"}
+
+  Note that in Line 4 we had to reverse the list of variables that @{ML
+  strip_alls} returned. The reason is that the head of the list the function
+  @{ML subst_bounds} takes is the replacement for @{ML "Bound 0"}, the next
+  element for @{ML "Bound 1"} and so on. 
+
+  Notice also that this function might introduce name clashes, since we
+  substitute just a variable with the name recorded in an abstraction. This
+  name is by no means unique. If clashes need to be avoided, then we should
+  use the function @{ML_ind dest_abs in Term}, which returns the body where
+  the lose de Bruijn index is replaced by a unique free variable. For example
+
+
+  @{ML_response_fake [display,gray]
+  "let
+  val body = Bound 0 $ Free (\"x\", @{typ nat})
+in
+  Term.dest_abs (\"x\", @{typ \"nat \<Rightarrow> bool\"}, body)
+end"
+  "(\"xa\", Free (\"xa\", \"nat \<Rightarrow> bool\") $ Free (\"x\", \"nat\"))"}
+
+  There are also many convenient functions that construct specific HOL-terms
+  in the structure @{ML_struct HOLogic}. For
+  example @{ML_ind mk_eq in HOLogic} constructs an equality out of two terms.
+  The types needed in this equality are calculated from the type of the
+  arguments. For example
+
+@{ML_response_fake [gray,display]
+"let
+  val eq = HOLogic.mk_eq (@{term \"True\"}, @{term \"False\"})
+in
+  string_of_term @{context} eq
+  |> tracing
+end"
+  "True = False"}
+*}
+
+text {*
+  \begin{readmore}
+  There are many functions in @{ML_file "Pure/term.ML"}, @{ML_file
+  "Pure/logic.ML"} and @{ML_file "HOL/Tools/hologic.ML"} that make manual
+  constructions of terms and types easier.
+  \end{readmore}
+
+  When constructing terms manually, there are a few subtle issues with
+  constants. They usually crop up when pattern matching terms or types, or
+  when constructing them. While it is perfectly ok to write the function
+  @{text is_true} as follows
+*}
+
+ML{*fun is_true @{term True} = true
+  | is_true _ = false*}
+
+text {*
+  this does not work for picking out @{text "\<forall>"}-quantified terms. Because
+  the function 
+*}
+
+ML{*fun is_all (@{term All} $ _) = true
+  | is_all _ = false*}
+
+text {* 
+  will not correctly match the formula @{prop[source] "\<forall>x::nat. P x"}: 
+
+  @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "false"}
+
+  The problem is that the @{text "@term"}-antiquotation in the pattern 
+  fixes the type of the constant @{term "All"} to be @{typ "('a \<Rightarrow> bool) \<Rightarrow> bool"} for 
+  an arbitrary, but fixed type @{typ "'a"}. A properly working alternative 
+  for this function is
+*}
+
+ML{*fun is_all (Const ("All", _) $ _) = true
+  | is_all _ = false*}
+
+text {* 
+  because now
+
+@{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "true"}
+
+  matches correctly (the first wildcard in the pattern matches any type and the
+  second any term).
+
+  However there is still a problem: consider the similar function that
+  attempts to pick out @{text "Nil"}-terms:
+*}
+
+ML{*fun is_nil (Const ("Nil", _)) = true
+  | is_nil _ = false *}
+
+text {* 
+  Unfortunately, also this function does \emph{not} work as expected, since
+
+  @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"}
+
+  The problem is that on the ML-level the name of a constant is more
+  subtle than you might expect. The function @{ML is_all} worked correctly,
+  because @{term "All"} is such a fundamental constant, which can be referenced
+  by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at
+
+  @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"}
+
+  the name of the constant @{text "Nil"} depends on the theory in which the
+  term constructor is defined (@{text "List"}) and also in which datatype
+  (@{text "list"}). Even worse, some constants have a name involving
+  type-classes. Consider for example the constants for @{term "zero"} and
+  \mbox{@{text "(op *)"}}:
+
+  @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"(op *)\"})" 
+ "(Const (\"HOL.zero_class.zero\", \<dots>), 
+ Const (\"HOL.times_class.times\", \<dots>))"}
+
+  While you could use the complete name, for example 
+  @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or
+  matching against @{text "Nil"}, this would make the code rather brittle. 
+  The reason is that the theory and the name of the datatype can easily change. 
+  To make the code more robust, it is better to use the antiquotation 
+  @{text "@{const_name \<dots>}"}. With this antiquotation you can harness the 
+  variable parts of the constant's name. Therefore a function for 
+  matching against constants that have a polymorphic type should 
+  be written as follows.
+*}
+
+ML{*fun is_nil_or_all (Const (@{const_name "Nil"}, _)) = true
+  | is_nil_or_all (Const (@{const_name "All"}, _) $ _) = true
+  | is_nil_or_all _ = false *}
+
+text {*
+  The antiquotation for properly referencing type constants is @{text "@{type_name \<dots>}"}.
+  For example
+
+  @{ML_response [display,gray]
+  "@{type_name \"list\"}" "\"List.list\""}
+
+  \footnote{\bf FIXME: Explain the following better; maybe put in a separate
+  section and link with the comment in the antiquotation section.}
+
+  Occasionally you have to calculate what the ``base'' name of a given
+  constant is. For this you can use the function @{ML_ind "Sign.extern_const"} or
+  @{ML_ind  Long_Name.base_name}. For example:
+
+  @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""}
+
+  The difference between both functions is that @{ML extern_const in Sign} returns
+  the smallest name that is still unique, whereas @{ML base_name in Long_Name} always
+  strips off all qualifiers.
+
+  \begin{readmore}
+  Functions about naming are implemented in @{ML_file "Pure/General/name_space.ML"};
+  functions about signatures in @{ML_file "Pure/sign.ML"}.
+  \end{readmore}
+
+  Although types of terms can often be inferred, there are many
+  situations where you need to construct types manually, especially  
+  when defining constants. For example the function returning a function 
+  type is as follows:
+
+*} 
+
+ML{*fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2]) *}
+
+text {* This can be equally written with the combinator @{ML_ind "-->" in Term} as: *}
+
+ML{*fun make_fun_type ty1 ty2 = ty1 --> ty2 *}
+
+text {*
+  If you want to construct a function type with more than one argument
+  type, then you can use @{ML_ind "--->" in Term}.
+*}
+
+ML{*fun make_fun_types tys ty = tys ---> ty *}
+
+text {*
+  A handy function for manipulating terms is @{ML_ind map_types in Term}: it takes a 
+  function and applies it to every type in a term. You can, for example,
+  change every @{typ nat} in a term into an @{typ int} using the function:
+*}
+
+ML{*fun nat_to_int ty =
+  (case ty of
+     @{typ nat} => @{typ int}
+   | Type (s, tys) => Type (s, map nat_to_int tys)
+   | _ => ty)*}
+
+text {*
+  Here is an example:
+
+@{ML_response_fake [display,gray] 
+"map_types nat_to_int @{term \"a = (1::nat)\"}" 
+"Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\")
+           $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"}
+
+  If you want to obtain the list of free type-variables of a term, you
+  can use the function @{ML_ind  add_tfrees in Term} 
+  (similarly @{ML_ind  add_tvars in Term} for the schematic type-variables). 
+  One would expect that such functions
+  take a term as input and return a list of types. But their type is actually 
+
+  @{text[display] "Term.term -> (string * Term.sort) list -> (string * Term.sort) list"}
+
+  that is they take, besides a term, also a list of type-variables as input. 
+  So in order to obtain the list of type-variables of a term you have to 
+  call them as follows
+
+  @{ML_response [gray,display]
+  "Term.add_tfrees @{term \"(a, b)\"} []"
+  "[(\"'b\", [\"HOL.type\"]), (\"'a\", [\"HOL.type\"])]"}
+
+  The reason for this definition is that @{ML add_tfrees in Term} can
+  be easily folded over a list of terms. Similarly for all functions
+  named @{text "add_*"} in @{ML_file "Pure/term.ML"}.
+
+  \begin{exercise}\label{fun:revsum}
+  Write a function @{text "rev_sum : term -> term"} that takes a
+  term of the form @{text "t\<^isub>1 + t\<^isub>2 + \<dots> + t\<^isub>n"} (whereby @{text "n"} might be one)
+  and returns the reversed sum @{text "t\<^isub>n + \<dots> + t\<^isub>2 + t\<^isub>1"}. Assume
+  the @{text "t\<^isub>i"} can be arbitrary expressions and also note that @{text "+"} 
+  associates to the left. Try your function on some examples. 
+  \end{exercise}
+
+  \begin{exercise}\label{fun:makesum}
+  Write a function that takes two terms representing natural numbers
+  in unary notation (like @{term "Suc (Suc (Suc 0))"}), and produces the
+  number representing their sum.
+  \end{exercise}
+
+  \begin{exercise}\label{ex:debruijn}
+  Implement the function, which we below name deBruijn, that depends on a natural
+  number n$>$0 and constructs terms of the form:
+  
+  \begin{center}
+  \begin{tabular}{r@ {\hspace{2mm}}c@ {\hspace{2mm}}l}
+  {\it rhs n} & $\dn$ & {\large$\bigwedge$}{\it i=1\ldots n.  P\,i}\\
+  {\it lhs n} & $\dn$ & {\large$\bigwedge$}{\it i=1\ldots n. P\,i = P (i + 1 mod n)}
+                        $\longrightarrow$ {\it rhs n}\\
+  {\it deBruijn n} & $\dn$ & {\it lhs n} $\longrightarrow$ {\it rhs n}\\
+  \end{tabular}
+  \end{center}
+
+  This function returns for n=3 the term
+
+  \begin{center}
+  \begin{tabular}{l}
+  (P 1 = P 2 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\wedge$\\
+  (P 2 = P 3 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\wedge$\\ 
+  (P 3 = P 1 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3
+  \end{tabular}
+  \end{center}
+
+  Make sure you use the functions defined in @{ML_file "HOL/Tools/hologic.ML"}
+  for constructing the terms for the logical connectives.\footnote{Thanks to Roy
+  Dyckhoff for suggesting this exercise and working out the details.} 
+  \end{exercise}
+*}
+
+section {* Unification and Matching *}
+
+text {* 
+  As seen earlier, Isabelle's terms and types may contain schematic term variables
+  (term-constructor @{ML Var}) and schematic type variables (term-constructor
+  @{ML TVar}). These variables stand for unknown entities, which can be made
+  more concrete by instantiations. Such instantiations might be a result of
+  unification or matching. While in case of types, unification and matching is
+  relatively straightforward, in case of terms the algorithms are
+  substantially more complicated, because terms need higher-order versions of
+  the unification and matching algorithms. Below we shall use the
+  antiquotations @{text "@{typ_pat \<dots>}"} and @{text "@{term_pat \<dots>}"} from
+  Section~\ref{sec:antiquote} in order to construct examples involving
+  schematic variables.
+
+  Let us begin with describing the unification and matching function for
+  types.  Both return type environments (ML-type @{ML_type "Type.tyenv"})
+  which map schematic type variables to types and sorts. Below we use the
+  function @{ML_ind typ_unify in Sign} from the structure @{ML_struct Sign}
+  for unifying the types @{text "?'a * ?'b"} and @{text "?'b list *
+  nat"}. This will produce the mapping, or type environment, @{text "[?'a :=
+  ?'b list, ?'b := nat]"}.
+*}
+
+ML %linenosgray{*val (tyenv_unif, _) = let
+  val ty1 = @{typ_pat "?'a * ?'b"}
+  val ty2 = @{typ_pat "?'b list * nat"}
+in
+  Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) 
+end*}
+
+text {* 
+  The environment @{ML_ind "Vartab.empty"} in line 5 stands for the empty type
+  environment, which is needed for starting the unification without any
+  (pre)instantiations. The @{text 0} is an integer index that will be explained
+  below. In case of failure @{ML typ_unify in Sign} will throw the exception
+  @{text TUNIFY}.  We can print out the resulting type environment bound to 
+  @{ML tyenv_unif} with the built-in function @{ML_ind dest in Vartab} from the
+  structure @{ML_struct Vartab}.
+
+  @{ML_response_fake [display,gray]
+  "Vartab.dest tyenv_unif"
+  "[((\"'a\", 0), ([\"HOL.type\"], \"?'b List.list\")), 
+ ((\"'b\", 0), ([\"HOL.type\"], \"nat\"))]"} 
+*}
+
+text_raw {*
+  \begin{figure}[t]
+  \begin{minipage}{\textwidth}
+  \begin{isabelle}*}
+ML{*fun pretty_helper aux env =
+  env |> Vartab.dest  
+      |> map ((fn (s1, s2) => s1 ^ " := " ^ s2) o aux) 
+      |> commas 
+      |> enclose "[" "]" 
+      |> tracing
+
+fun pretty_tyenv ctxt tyenv =
+let
+  fun get_typs (v, (s, T)) = (TVar (v, s), T)
+  val print = pairself (Syntax.string_of_typ ctxt)
+in 
+  pretty_helper (print o get_typs) tyenv
+end*}
+text_raw {*
+  \end{isabelle}
+  \end{minipage}
+  \caption{A pretty printing function for type environments, which are 
+  produced by unification and matching.\label{fig:prettyenv}}
+  \end{figure}
+*}
+
+text {*
+  The first components in this list stand for the schematic type variables and
+  the second are the associated sorts and types. In this example the sort is
+  the default sort @{text "HOL.type"}. Instead of @{ML "Vartab.dest"}, we will
+  use in what follows our own pretty-printing function from
+  Figure~\ref{fig:prettyenv} for @{ML_type "Type.tyenv"}s. For the type
+  environment in the example this function prints out the more legible:
+
+
+  @{ML_response_fake [display, gray]
+  "pretty_tyenv @{context} tyenv_unif"
+  "[?'a := ?'b list, ?'b := nat]"}
+
+  The way the unification function @{ML typ_unify in Sign} is implemented 
+  using an initial type environment and initial index makes it easy to
+  unify more than two terms. For example 
+*}
+
+ML %linenosgray{*val (tyenvs, _) = let
+  val tys1 = (@{typ_pat "?'a"}, @{typ_pat "?'b list"})
+  val tys2 = (@{typ_pat "?'b"}, @{typ_pat "nat"})
+in
+  fold (Sign.typ_unify @{theory}) [tys1, tys2] (Vartab.empty, 0) 
+end*}
+
+text {*
+  The index @{text 0} in Line 5 is the maximal index of the schematic type
+  variables occurring in @{text tys1} and @{text tys2}. This index will be
+  increased whenever a new schematic type variable is introduced during
+  unification.  This is for example the case when two schematic type variables
+  have different, incomparable sorts. Then a new schematic type variable is
+  introduced with the combined sorts. To show this let us assume two sorts,
+  say @{text "s1"} and @{text "s2"}, which we attach to the schematic type
+  variables @{text "?'a"} and @{text "?'b"}. Since we do not make any
+  assumption about the sorts, they are incomparable.
+*}
+
+ML{*val (tyenv, index) = let
+  val ty1 = @{typ_pat "?'a::s1"}
+  val ty2 = @{typ_pat "?'b::s2"}
+in
+  Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) 
+end*}
+
+text {*
+  To print out the result type environment we switch on the printing 
+  of sort information by setting @{ML_ind show_sorts in Syntax} to 
+  true. This allows us to inspect the typing environment.
+
+  @{ML_response_fake [display,gray]
+  "pretty_tyenv @{context} tyenv"
+  "[?'a::s1 := ?'a1::{s1, s2}, ?'b::s2 := ?'a1::{s1, s2}]"}
+
+  As can be seen, the type variables @{text "?'a"} and @{text "?'b"} are instantiated
+  with a new type variable @{text "?'a1"} with sort @{text "{s1, s2}"}. Since a new
+  type variable has been introduced the @{ML index}, originally being @{text 0}, 
+  has been increased to @{text 1}.
+
+  @{ML_response [display,gray]
+  "index"
+  "1"}
+
+  Let us now return to the unification problem @{text "?'a * ?'b"} and 
+  @{text "?'b list * nat"} from the beginning of this section, and the 
+  calculated type environment @{ML tyenv_unif}:
+
+  @{ML_response_fake [display, gray]
+  "pretty_tyenv @{context} tyenv_unif"
+  "[?'a := ?'b list, ?'b := nat]"}
+
+  Observe that the type environment which the function @{ML typ_unify in
+  Sign} returns is in \emph{not} an instantiation in fully solved form: while @{text
+  "?'b"} is instantiated to @{typ nat}, this is not propagated to the
+  instantiation for @{text "?'a"}.  In unification theory, this is often
+  called an instantiation in \emph{triangular form}. These triangular 
+  instantiations, or triangular type environments, are used because of 
+  performance reasons. To apply such a type environment to a type, say @{text "?'a *
+  ?'b"}, you should use the function @{ML_ind norm_type in Envir}:
+
+  @{ML_response_fake [display, gray]
+  "Envir.norm_type tyenv_unif @{typ_pat \"?'a * ?'b\"}"
+  "nat list * nat"}
+
+  Matching of types can be done with the function @{ML_ind typ_match in Sign}
+  also from the structure @{ML_struct Sign}. This function returns a @{ML_type
+  Type.tyenv} as well, but might raise the exception @{text TYPE_MATCH} in case
+  of failure. For example
+*}
+
+ML{*val tyenv_match = let
+  val pat = @{typ_pat "?'a * ?'b"}
+  and ty  = @{typ_pat "bool list * nat"}
+in
+  Sign.typ_match @{theory} (pat, ty) Vartab.empty 
+end*}
+
+text {*
+  Printing out the calculated matcher gives
+
+  @{ML_response_fake [display,gray]
+  "pretty_tyenv @{context} tyenv_match"
+  "[?'a := bool list, ?'b := nat]"}
+  
+  Unlike unification, which uses the function @{ML norm_type in Envir}, 
+  applying the matcher to a type needs to be done with the function
+  @{ML_ind subst_type in Envir}. For example
+
+  @{ML_response_fake [display, gray]
+  "Envir.subst_type tyenv_match @{typ_pat \"?'a * ?'b\"}"
+  "bool list * nat"}
+
+  Be careful to observe the difference: use always 
+  @{ML subst_type in Envir} for matchers and @{ML norm_type in Envir} 
+  for unifiers. To show the difference, let us calculate the 
+  following matcher:
+*}
+
+ML{*val tyenv_match' = let
+  val pat = @{typ_pat "?'a * ?'b"}
+  and ty  = @{typ_pat "?'b list * nat"}
+in
+  Sign.typ_match @{theory} (pat, ty) Vartab.empty 
+end*}
+
+text {*
+  Now @{ML tyenv_unif} is equal to @{ML tyenv_match'}. If we apply 
+  @{ML norm_type in Envir} to the type @{text "?'a * ?'b"} we obtain
+
+  @{ML_response_fake [display, gray]
+  "Envir.norm_type tyenv_match' @{typ_pat \"?'a * ?'b\"}"
+  "nat list * nat"}
+
+  which does not solve the matching problem, and if
+  we apply @{ML subst_type in Envir} to the same type we obtain
+
+  @{ML_response_fake [display, gray]
+  "Envir.subst_type tyenv_unif @{typ_pat \"?'a * ?'b\"}"
+  "?'b list * nat"}
+  
+  which does not solve the unification problem.
+
+  \begin{readmore}
+  Unification and matching for types is implemented
+  in @{ML_file "Pure/type.ML"}. The ``interface'' functions for them
+  are in @{ML_file "Pure/sign.ML"}. Matching and unification produce type environments
+  as results. These are implemented in @{ML_file "Pure/envir.ML"}.
+  This file also includes the substitution and normalisation functions,
+  which apply a type environment to a type. Type environments are lookup 
+  tables which are implemented in @{ML_file "Pure/term_ord.ML"}.
+  \end{readmore}
+*}
+
+text {*
+  Unification and matching of terms is substantially more complicated than the
+  type-case. The reason is that terms have abstractions and, in this context,  
+  unification or matching modulo plain equality is often not meaningful. 
+  Nevertheless, Isabelle implements the function @{ML_ind
+  first_order_match in Pattern} for terms.  This matching function returns a
+  type environment and a term environment.  To pretty print the latter we use
+  the function @{text "pretty_env"}:
+*}
+
+ML{*fun pretty_env ctxt env =
+let
+  fun get_trms (v, (T, t)) = (Var (v, T), t) 
+  val print = pairself (string_of_term ctxt)
+in
+  pretty_helper (print o get_trms) env 
+end*}
+
+text {*
+  As can be seen from the @{text "get_trms"}-function, a term environment associates 
+  a schematic term variable with a type and a term.  An example of a first-order 
+  matching problem is the term @{term "P (\<lambda>a b. Q b a)"} and the pattern 
+  @{text "?X ?Y"}.
+*}
+
+ML{*val (_, fo_env) = let
+  val fo_pat = @{term_pat "(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y"}
+  val trm_a = @{term "P::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool"} 
+  val trm_b = @{term "\<lambda>a b. (Q::nat\<Rightarrow>nat\<Rightarrow>nat) b a"}
+  val init = (Vartab.empty, Vartab.empty) 
+in
+  Pattern.first_order_match @{theory} (fo_pat, trm_a $ trm_b) init
+end *}
+
+text {*
+  In this example we annotated explicitly types because then 
+  the type environment is empty and can be ignored. The 
+  resulting term environment is
+
+  @{ML_response_fake [display, gray]
+  "pretty_env @{context} fo_env"
+  "[?X := P, ?Y := \<lambda>a b. Q b a]"}
+
+  The matcher can be applied to a term using the function @{ML_ind subst_term
+  in Envir} (remember the same convention for types applies to terms: @{ML
+  subst_term in Envir} is for matchers and @{ML norm_term in Envir} for
+  unifiers). The function @{ML subst_term in Envir} expects a type environment,
+  which is set to empty in the example below, and a term environment.
+
+  @{ML_response_fake [display, gray]
+  "let
+  val trm = @{term_pat \"(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y\"}
+in
+  Envir.subst_term (Vartab.empty, fo_env) trm
+  |> string_of_term @{context}
+  |> tracing
+end"
+  "P (\<lambda>a b. Q b a)"}
+
+  First-order matching is useful for matching against applications and
+  variables. It can deal also with abstractions and a limited form of
+  alpha-equivalence, but this kind of matching should be used with care, since
+  it is not clear whether the result is meaningful. A meaningful example is
+  matching @{text "\<lambda>x. P x"} against the pattern @{text "\<lambda>y. ?X y"}. In this
+  case, first-order matching produces @{text "[?X := P]"}.
+
+  @{ML_response_fake [display, gray]
+  "let
+  val fo_pat = @{term_pat \"\<lambda>y. (?X::nat\<Rightarrow>bool) y\"}
+  val trm = @{term \"\<lambda>x. (P::nat\<Rightarrow>bool) x\"} 
+  val init = (Vartab.empty, Vartab.empty) 
+in
+  Pattern.first_order_match @{theory} (fo_pat, trm) init
+  |> snd 
+  |> pretty_env @{context} 
+end"
+  "[?X := P]"}
+*}
+
+text {*
+  Unification of abstractions is more thoroughly studied in the context
+  of higher-order pattern unification and higher-order pattern matching.  A
+  \emph{\index*{pattern}} is an abstraction term whose ``head symbol'' (that is the
+  first symbol under an abstraction) is either a constant, a schematic or a free
+  variable. If it is a schematic variable then it can be only applied with
+  distinct bound variables. This excludes terms where a schematic variable is an
+  argument of another one and where a schematic variable is applied
+  twice with the same bound variable. The function @{ML_ind pattern in Pattern}
+  in the structure @{ML_struct Pattern} tests whether a term satisfies these
+  restrictions.
+
+  @{ML_response [display, gray]
+  "let
+  val trm_list = 
+        [@{term_pat \"?X\"},              @{term_pat \"a\"},
+         @{term_pat \"\<lambda>a b. ?X a b\"},    @{term_pat \"\<lambda>a b. (op +) a b\"},
+         @{term_pat \"\<lambda>a. (op +) a ?Y\"}, @{term_pat \"?X ?Y\"},
+         @{term_pat \"\<lambda>a b. ?X a b ?Y\"}, @{term_pat \"\<lambda>a. ?X a a\"}] 
+in
+  map Pattern.pattern trm_list
+end"
+  "[true, true, true, true, true, false, false, false]"}
+
+  The point of the restriction to patterns is that unification and matching 
+  are decidable and produce most general unifiers, respectively matchers. 
+  In this way, matching and unification can be implemented as functions that 
+  produce a type and term environment (unification actually returns a 
+  record of type @{ML_type Envir.env} containing a maxind, a type environment 
+  and a term environment). The corresponding functions are @{ML_ind match in Pattern},
+  and @{ML_ind unify in Pattern} both implemented in the structure
+  @{ML_struct Pattern}. An example for higher-order pattern unification is
+
+  @{ML_response_fake [display, gray]
+  "let
+  val trm1 = @{term_pat \"\<lambda>x y. g (?X y x) (f (?Y x))\"}
+  val trm2 = @{term_pat \"\<lambda>u v. g u (f u)\"}
+  val init = Envir.empty 0
+  val env = Pattern.unify @{theory} (trm1, trm2) init
+in
+  pretty_env @{context} (Envir.term_env env)
+end"
+  "[?X := \<lambda>y x. x, ?Y := \<lambda>x. x]"}
+
+  The function @{ML_ind "Envir.empty"} generates a record with a specified
+  max-index for the schematic variables (in the example the index is @{text
+  0}) and empty type and term environments. The function @{ML_ind
+  "Envir.term_env"} pulls out the term environment from the result record. The
+  function for type environment is @{ML_ind "Envir.type_env"}. An assumption of
+  this function is that the terms to be unified have already the same type. In
+  case of failure, the exceptions that are raised are either @{text Pattern},
+  @{text MATCH} or @{text Unif}.
+
+  As mentioned before, unrestricted higher-order unification, respectively
+  higher-order matching, is in general undecidable and might also not posses a
+  single most general solution. Therefore Isabelle implements the unification
+  function @{ML_ind unifiers in Unify} so that it returns a lazy list of
+  potentially infinite unifiers.  An example is as follows
+*}
+
+ML{*val uni_seq =
+let 
+  val trm1 = @{term_pat "?X ?Y"}
+  val trm2 = @{term "f a"}
+  val init = Envir.empty 0
+in
+  Unify.unifiers (@{theory}, init, [(trm1, trm2)])
+end *}
+
+text {*
+  The unifiers can be extracted from the lazy sequence using the 
+  function @{ML_ind "Seq.pull"}. In the example we obtain three 
+  unifiers @{text "un1\<dots>un3"}.
+*}
+
+ML{*val SOME ((un1, _), next1) = Seq.pull uni_seq;
+val SOME ((un2, _), next2) = Seq.pull next1;
+val SOME ((un3, _), next3) = Seq.pull next2;
+val NONE = Seq.pull next3 *}
+
+text {*
+  \footnote{\bf FIXME: what is the list of term pairs in the unifier: flex-flex pairs?}
+
+  We can print them out as follows.
+
+  @{ML_response_fake [display, gray]
+  "pretty_env @{context} (Envir.term_env un1);
+pretty_env @{context} (Envir.term_env un2);
+pretty_env @{context} (Envir.term_env un3)"
+  "[?X := \<lambda>a. a, ?Y := f a]
+[?X := f, ?Y := a]
+[?X := \<lambda>b. f a]"}
+
+
+  In case of failure the function @{ML_ind unifiers in Unify} does not raise
+  an exception, rather returns the empty sequence. For example
+
+  @{ML_response [display, gray]
+"let 
+  val trm1 = @{term \"a\"}
+  val trm2 = @{term \"b\"}
+  val init = Envir.empty 0
+in
+  Unify.unifiers (@{theory}, init, [(trm1, trm2)])
+  |> Seq.pull
+end"
+"NONE"}
+
+  In order to find a
+  reasonable solution for a unification problem, Isabelle also tries first to
+  solve the problem by higher-order pattern unification. 
+
+  For higher-order
+  matching the function is called @{ML_ind matchers in Unify} implemented
+  in the structure @{ML_struct Unify}. Also this
+  function returns sequences with possibly more than one matcher.
+  Like @{ML unifiers in Unify}, this function does not raise an exception
+  in case of failure, but returns an empty sequence. It also first tries 
+  out whether the matching problem can be solved by first-order matching.
+
+  \begin{readmore}
+  Unification and matching of higher-order patterns is implemented in 
+  @{ML_file "Pure/pattern.ML"}. This file also contains a first-order matcher
+  for terms. Full higher-order unification is implemented
+  in @{ML_file "Pure/unify.ML"}. It uses lazy sequences which are implemented
+  in @{ML_file "Pure/General/seq.ML"}.
+  \end{readmore}
+*}
+
+section {* Sorts (TBD) *}
+
+
+section {* Type-Checking\label{sec:typechecking} *}
+
+text {* 
+  Remember Isabelle follows the Church-style typing for terms, i.e., a term contains 
+  enough typing information (constants, free variables and abstractions all have typing 
+  information) so that it is always clear what the type of a term is. 
+  Given a well-typed term, the function @{ML_ind type_of in Term} returns the 
+  type of a term. Consider for example:
+
+  @{ML_response [display,gray] 
+  "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"}
+
+  To calculate the type, this function traverses the whole term and will
+  detect any typing inconsistency. For example changing the type of the variable 
+  @{term "x"} from @{typ "nat"} to @{typ "int"} will result in the error message: 
+
+  @{ML_response_fake [display,gray] 
+  "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" 
+  "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"}
+
+  Since the complete traversal might sometimes be too costly and
+  not necessary, there is the function @{ML_ind fastype_of in Term}, which 
+  also returns the type of a term.
+
+  @{ML_response [display,gray] 
+  "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"}
+
+  However, efficiency is gained on the expense of skipping some tests. You 
+  can see this in the following example
+
+   @{ML_response [display,gray] 
+  "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" "bool"}
+
+  where no error is detected.
+
+  Sometimes it is a bit inconvenient to construct a term with 
+  complete typing annotations, especially in cases where the typing 
+  information is redundant. A short-cut is to use the ``place-holder'' 
+  type @{ML_ind dummyT in Term} and then let type-inference figure out the 
+  complete type. An example is as follows:
+
+  @{ML_response_fake [display,gray] 
+"let
+  val c = Const (@{const_name \"plus\"}, dummyT) 
+  val o = @{term \"1::nat\"} 
+  val v = Free (\"x\", dummyT)
+in   
+  Syntax.check_term @{context} (c $ o $ v)
+end"
+"Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $
+  Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"}
+
+  Instead of giving explicitly the type for the constant @{text "plus"} and the free 
+  variable @{text "x"}, type-inference fills in the missing information.
+
+  \begin{readmore}
+  See @{ML_file "Pure/Syntax/syntax.ML"} where more functions about reading,
+  checking and pretty-printing of terms are defined. Functions related to
+  type-inference are implemented in @{ML_file "Pure/type.ML"} and 
+  @{ML_file "Pure/type_infer.ML"}. 
+  \end{readmore}
+
+  \footnote{\bf FIXME: say something about sorts.}
+  \footnote{\bf FIXME: give a ``readmore''.}
+
+  \begin{exercise}
+  Check that the function defined in Exercise~\ref{fun:revsum} returns a
+  result that type-checks. See what happens to the  solutions of this 
+  exercise given in Appendix \ref{ch:solutions} when they receive an 
+  ill-typed term as input.
+  \end{exercise}
+*}
+
+section {* Certified Terms and Certified Types *}
+
+text {*
+  You can freely construct and manipulate @{ML_type "term"}s and @{ML_type
+  typ}es, since they are just arbitrary unchecked trees. However, you
+  eventually want to see if a term is well-formed, or type-checks, relative to
+  a theory.  Type-checking is done via the function @{ML_ind cterm_of in Thm}, which
+  converts a @{ML_type term} into a @{ML_type cterm}, a \emph{certified}
+  term. Unlike @{ML_type term}s, which are just trees, @{ML_type "cterm"}s are
+  abstract objects that are guaranteed to be type-correct, and they can only
+  be constructed via ``official interfaces''.
+
+  Certification is always relative to a theory context. For example you can 
+  write:
+
+  @{ML_response_fake [display,gray] 
+  "cterm_of @{theory} @{term \"(a::nat) + b = c\"}" 
+  "a + b = c"}
+
+  This can also be written with an antiquotation:
+
+  @{ML_response_fake [display,gray] 
+  "@{cterm \"(a::nat) + b = c\"}" 
+  "a + b = c"}
+
+  Attempting to obtain the certified term for
+
+  @{ML_response_fake_both [display,gray] 
+  "@{cterm \"1 + True\"}" 
+  "Type unification failed \<dots>"}
+
+  yields an error (since the term is not typable). A slightly more elaborate
+  example that type-checks is:
+
+@{ML_response_fake [display,gray] 
+"let
+  val natT = @{typ \"nat\"}
+  val zero = @{term \"0::nat\"}
+  val plus = Const (@{const_name plus}, [natT, natT] ---> natT)
+in
+  cterm_of @{theory} (plus $ zero $ zero)
+end" 
+  "0 + 0"}
+
+  In Isabelle not just terms need to be certified, but also types. For example, 
+  you obtain the certified type for the Isabelle type @{typ "nat \<Rightarrow> bool"} on 
+  the ML-level as follows:
+
+  @{ML_response_fake [display,gray]
+  "ctyp_of @{theory} (@{typ nat} --> @{typ bool})"
+  "nat \<Rightarrow> bool"}
+
+  or with the antiquotation:
+
+  @{ML_response_fake [display,gray]
+  "@{ctyp \"nat \<Rightarrow> bool\"}"
+  "nat \<Rightarrow> bool"}
+
+  Since certified terms are, unlike terms, abstract objects, we cannot
+  pattern-match against them. However, we can construct them. For example
+  the function @{ML_ind capply in Thm} produces a certified application.
+
+  @{ML_response_fake [display,gray]
+  "Thm.capply @{cterm \"P::nat \<Rightarrow> bool\"} @{cterm \"3::nat\"}"
+  "P 3"}
+
+  Similarly the function @{ML_ind list_comb in Drule} from the structure @{ML_struct Drule}
+  applies a list of @{ML_type cterm}s.
+
+  @{ML_response_fake [display,gray]
+  "let
+  val chead = @{cterm \"P::unit \<Rightarrow> nat \<Rightarrow> bool\"}
+  val cargs = [@{cterm \"()\"}, @{cterm \"3::nat\"}]
+in
+  Drule.list_comb (chead, cargs)
+end"
+  "P () 3"}
+
+  \begin{readmore}
+  For functions related to @{ML_type cterm}s and @{ML_type ctyp}s see 
+  the files @{ML_file "Pure/thm.ML"}, @{ML_file "Pure/more_thm.ML"} and
+  @{ML_file "Pure/drule.ML"}.
+  \end{readmore}
+*}
+
+section {* Theorems *}
+
+text {*
+  Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} 
+  that can only be built by going through interfaces. As a consequence, every proof 
+  in Isabelle is correct by construction. This follows the tradition of the LCF-approach.
+
+
+  To see theorems in ``action'', let us give a proof on the ML-level for the following 
+  statement:
+*}
+
+  lemma 
+    assumes assm\<^isub>1: "\<And>(x::nat). P x \<Longrightarrow> Q x" 
+    and     assm\<^isub>2: "P t"
+    shows "Q t"(*<*)oops(*>*) 
+
+text {*
+  The corresponding ML-code is as follows:
+*}
+
+ML{*val my_thm = 
+let
+  val assm1 = @{cprop "\<And>(x::nat). P x \<Longrightarrow> Q x"}
+  val assm2 = @{cprop "(P::nat \<Rightarrow> bool) t"}
+
+  val Pt_implies_Qt = 
+        assume assm1
+        |> forall_elim @{cterm "t::nat"}
+  
+  val Qt = implies_elim Pt_implies_Qt (assume assm2)
+in
+  Qt 
+  |> implies_intr assm2
+  |> implies_intr assm1
+end*}
+
+text {* 
+  If we print out the value of @{ML my_thm} then we see only the 
+  final statement of the theorem.
+
+  @{ML_response_fake [display, gray]
+  "tracing (string_of_thm @{context} my_thm)"
+  "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}
+
+  However, internally the code-snippet constructs the following 
+  proof.
+
+  \[
+  \infer[(@{text "\<Longrightarrow>"}$-$intro)]{\vdash @{prop "(\<And>x. P x \<Longrightarrow> Q x) \<Longrightarrow> P t \<Longrightarrow> Q t"}}
+    {\infer[(@{text "\<Longrightarrow>"}$-$intro)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "P t \<Longrightarrow> Q t"}}
+       {\infer[(@{text "\<Longrightarrow>"}$-$elim)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"}, @{prop "P t"} \vdash @{prop "Q t"}}
+          {\infer[(@{text "\<And>"}$-$elim)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "P t \<Longrightarrow> Q t"}}
+                 {\infer[(assume)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "\<And>x. P x \<Longrightarrow> Q x"}}{}}
+                 &
+           \infer[(assume)]{@{prop "P t"} \vdash @{prop "P t"}}{}
+          }
+       }
+    }
+  \]
+
+  While we obtained a theorem as result, this theorem is not
+  yet stored in Isabelle's theorem database. Consequently, it cannot be 
+  referenced on the user level. One way to store it in the theorem database is
+  by using the function @{ML_ind note in Local_Theory}.\footnote{\bf FIXME: make sure a pointer
+  to the section about local-setup is given earlier.}
+*}
+
+local_setup %gray {*
+  Local_Theory.note ((@{binding "my_thm"}, []), [my_thm]) #> snd *}
+
+text {*
+  The fourth argument of @{ML note in Local_Theory} is the list of theorems we
+  want to store under a name. We can store more than one under a single name. 
+  The first argument @{ML_ind theoremK in Thm} is
+  a kind indicator, which classifies the theorem. There are several such kind
+  indicators: for a theorem arising from a definition you should use @{ML_ind
+  definitionK in Thm}, and for
+  ``normal'' theorems the kinds @{ML_ind theoremK in Thm} or @{ML_ind lemmaK
+  in Thm}.  The second argument of @{ML note in Local_Theory} is the name under
+  which we store the theorem or theorems. The third argument can contain a
+  list of theorem attributes, which we will explain in detail in
+  Section~\ref{sec:attributes}. Below we just use one such attribute for
+  adding the theorem to the simpset:
+*}
+
+local_setup %gray {*
+  Local_Theory.note ((@{binding "my_thm_simp"}, 
+       [Attrib.internal (K Simplifier.simp_add)]), [my_thm]) #> snd *}
+
+text {*
+  Note that we have to use another name under which the theorem is stored,
+  since Isabelle does not allow us to call  @{ML_ind note in Local_Theory} twice
+  with the same name. The attribute needs to be wrapped inside the function @{ML_ind
+  internal in Attrib} from the structure @{ML_struct Attrib}. If we use the function 
+  @{ML get_thm_names_from_ss} from
+  the previous chapter, we can check whether the theorem has actually been
+  added.
+
+
+  @{ML_response [display,gray]
+  "let
+  fun pred s = match_string \"my_thm_simp\" s
+in
+  exists pred (get_thm_names_from_ss @{simpset})
+end"
+  "true"}
+
+  The main point of storing the theorems @{thm [source] my_thm} and @{thm
+  [source] my_thm_simp} is that they can now also be referenced with the
+  \isacommand{thm}-command on the user-level of Isabelle
+
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "my_thm"}\isanewline
+   @{text ">"}~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}
+  \end{isabelle}
+
+  or with the @{text "@{thm \<dots>}"}-antiquotation on the ML-level. Otherwise the 
+  user has no access to these theorems. 
+
+  Recall that Isabelle does not let you call @{ML note in Local_Theory} twice
+  with the same theorem name. In effect, once a theorem is stored under a name, 
+  this association is fixed. While this is a ``safety-net'' to make sure a
+  theorem name refers to a particular theorem or collection of theorems, it is 
+  also a bit too restrictive in cases where a theorem name should refer to a 
+  dynamically expanding list of theorems (like a simpset). Therefore Isabelle 
+  also implements a mechanism where a theorem name can refer to a custom theorem 
+  list. For this you can use the function @{ML_ind add_thms_dynamic in PureThy}. 
+  To see how it works let us assume we defined our own theorem list @{text MyThmList}.
+*}
+
+ML{*structure MyThmList = Generic_Data
+  (type T = thm list
+   val empty = []
+   val extend = I
+   val merge = merge Thm.eq_thm_prop)
+
+fun update thm = Context.theory_map (MyThmList.map (Thm.add_thm thm))*}
+
+text {*
+  \footnote{\bf explain @{ML_ind add_thm in Thm} and @{ML_ind eq_thm_prop in Thm}.}
+
+  The function @{ML update} allows us to update the theorem list, for example
+  by adding the theorem @{thm [source] TrueI}.
+*}
+
+setup %gray {* update @{thm TrueI} *}
+ 
+text {*
+  We can now install the theorem list so that it is visible to the user and 
+  can be refered to by a theorem name. For this need to call 
+  @{ML_ind add_thms_dynamic in PureThy}
+*}
+
+setup %gray {* 
+  PureThy.add_thms_dynamic (@{binding "mythmlist"}, MyThmList.get) 
+*}
+
+text {*
+  with a name and a function that accesses the theorem list. Now if the
+  user issues the command
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "mythmlist"}\\
+  @{text "> True"}
+  \end{isabelle}
+
+  the current content of the theorem list is displayed. If more theorems are stored in 
+  the list, say
+*}
+
+setup %gray {* update @{thm FalseE} *}
+
+text {*
+  then the same command produces
+  
+  \begin{isabelle}
+  \isacommand{thm}~@{text "mythmlist"}\\
+  @{text "> False \<Longrightarrow> ?P"}\\
+  @{text "> True"}
+  \end{isabelle}
+
+  There is a multitude of functions in the structures @{ML_struct Thm} and @{ML_struct Drule} 
+  for managing or manipulating theorems. For example 
+  we can test theorems for alpha equality. Suppose you proved the following three 
+  theorems.
+*}
+
+lemma
+  shows thm1: "\<forall>x. P x" 
+  and   thm2: "\<forall>y. P y" 
+  and   thm3: "\<forall>y. Q y" sorry
+
+text {*
+  Testing them for alpha equality using the function @{ML_ind eq_thm in Thm} produces:
+
+  @{ML_response [display,gray]
+"(Thm.eq_thm (@{thm thm1}, @{thm thm2}),
+ Thm.eq_thm (@{thm thm2}, @{thm thm3}))"
+"(true, false)"}
+
+  Many functions destruct theorems into @{ML_type cterm}s. For example
+  the functions @{ML_ind lhs_of in Thm} and @{ML_ind rhs_of in Thm} return 
+  the left and right-hand side, respectively, of a meta-equality.
+
+  @{ML_response_fake [display,gray]
+  "let
+  val eq = @{thm True_def}
+in
+  (Thm.lhs_of eq, Thm.rhs_of eq) 
+  |> pairself (string_of_cterm @{context})
+end"
+  "(True, (\<lambda>x. x) = (\<lambda>x. x))"}
+
+  Other function produce terms that can be pattern-matched. 
+  Suppose the following two theorems.
+*}
+
+lemma  
+  shows foo_test1: "A \<Longrightarrow> B \<Longrightarrow> C" 
+  and   foo_test2: "A \<longrightarrow> B \<longrightarrow> C" sorry
+
+text {*
+  We can destruct them into premises and conclusions as follows. 
+
+ @{ML_response_fake [display,gray]
+"let
+  val ctxt = @{context}
+  fun prems_and_concl thm =
+     [\"Premises: \"   ^ (string_of_terms ctxt (Thm.prems_of thm))] @ 
+     [\"Conclusion: \" ^ (string_of_term ctxt (Thm.concl_of thm))]
+     |> cat_lines
+     |> tracing
+in
+  prems_and_concl @{thm foo_test1};
+  prems_and_concl @{thm foo_test2}
+end"
+"Premises: ?A, ?B
+Conclusion: ?C
+Premises: 
+Conclusion: ?A \<longrightarrow> ?B \<longrightarrow> ?C"}
+
+  Note that in the second case, there is no premise.
+
+  \begin{readmore}
+  The basic functions for theorems are defined in
+  @{ML_file "Pure/thm.ML"}, @{ML_file "Pure/more_thm.ML"} and @{ML_file "Pure/drule.ML"}. 
+  \end{readmore}
+
+  Although we will explain the simplifier in more detail as tactic in 
+  Section~\ref{sec:simplifier}, the simplifier 
+  can be used to work directly over theorems, for example to unfold definitions. To show
+  this, we build the theorem @{term "True \<equiv> True"} (Line 1) and then 
+  unfold the constant @{term "True"} according to its definition (Line 2).
+
+  @{ML_response_fake [display,gray,linenos]
+  "Thm.reflexive @{cterm \"True\"}
+  |> Simplifier.rewrite_rule [@{thm True_def}]
+  |> string_of_thm @{context}
+  |> tracing"
+  "(\<lambda>x. x) = (\<lambda>x. x) \<equiv> (\<lambda>x. x) = (\<lambda>x. x)"}
+
+  Often it is necessary to transform theorems to and from the object 
+  logic, that is replacing all @{text "\<longrightarrow>"} and @{text "\<forall>"} by @{text "\<Longrightarrow>"} 
+  and @{text "\<And>"}, or the other way around.  A reason for such a transformation 
+  might be stating a definition. The reason is that definitions can only be 
+  stated using object logic connectives, while theorems using the connectives 
+  from the meta logic are more convenient for reasoning. Therefore there are
+  some build in functions which help with these transformations. The function 
+  @{ML_ind rulify in ObjectLogic} 
+  replaces all object connectives by equivalents in the meta logic. For example
+
+  @{ML_response_fake [display, gray]
+  "ObjectLogic.rulify @{thm foo_test2}"
+  "\<lbrakk>?A; ?B\<rbrakk> \<Longrightarrow> ?C"}
+
+  The transformation in the other direction can be achieved with function
+  @{ML_ind atomize in ObjectLogic} and the following code.
+
+  @{ML_response_fake [display,gray]
+  "let
+  val thm = @{thm foo_test1}
+  val meta_eq = ObjectLogic.atomize (cprop_of thm)
+in
+  MetaSimplifier.rewrite_rule [meta_eq] thm
+end"
+  "?A \<longrightarrow> ?B \<longrightarrow> ?C"}
+
+  In this code the function @{ML atomize in ObjectLogic} produces 
+  a meta-equation between the given theorem and the theorem transformed
+  into the object logic. The result is the theorem with object logic 
+  connectives. However, in order to completely transform a theorem
+  involving meta variables, such as @{thm [source] list.induct}, which 
+  is of the form 
+
+  @{thm [display] list.induct}
+
+  we have to first abstract over the meta variables @{text "?P"} and 
+  @{text "?list"}. For this we can use the function 
+  @{ML_ind forall_intr_vars in Drule}. This allows us to implement the
+  following function for atomizing a theorem.
+*}
+
+ML{*fun atomize_thm thm =
+let
+  val thm' = forall_intr_vars thm
+  val thm'' = ObjectLogic.atomize (cprop_of thm')
+in
+  MetaSimplifier.rewrite_rule [thm''] thm'
+end*}
+
+text {*
+  This function produces for the theorem @{thm [source] list.induct}
+
+  @{ML_response_fake [display, gray]
+  "atomize_thm @{thm list.induct}"
+  "\<forall>P list. P [] \<longrightarrow> (\<forall>a list. P list \<longrightarrow> P (a # list)) \<longrightarrow> P list"}
+
+  \footnote{\bf FIXME: say someting about @{ML_ind standard in Drule}.}
+
+  Theorems can also be produced from terms by giving an explicit proof. 
+  One way to achieve this is by using the function @{ML_ind prove in Goal}
+  in the structure @{ML_struct Goal}. For example below we use this function
+  to prove the term @{term "P \<Longrightarrow> P"}.
+  
+  @{ML_response_fake [display,gray]
+  "let
+  val trm = @{term \"P \<Longrightarrow> P::bool\"}
+  val tac = K (atac 1)
+in
+  Goal.prove @{context} [\"P\"] [] trm tac
+end"
+  "?P \<Longrightarrow> ?P"}
+
+  This function takes first a context and second a list of strings. This list
+  specifies which variables should be turned into schematic variables once the term
+  is proved.  The fourth argument is the term to be proved. The fifth is a
+  corresponding proof given in form of a tactic (we explain tactics in
+  Chapter~\ref{chp:tactical}). In the code above, the tactic proves the theorem
+  by assumption. As before this code will produce a theorem, but the theorem
+  is not yet stored in the theorem database. 
+
+  While the LCF-approach of going through interfaces ensures soundness in Isabelle, there
+  is the function @{ML_ind make_thm in Skip_Proof} in the structure 
+  @{ML_struct Skip_Proof} that allows us to turn any proposition into a theorem.
+  Potentially making the system unsound.  This is sometimes useful for developing 
+  purposes, or when explicit proof construction should be omitted due to performace 
+  reasons. An example of this function is as follows:
+
+  @{ML_response_fake [display, gray]
+  "Skip_Proof.make_thm @{theory} @{prop \"True = False\"}"
+  "True = False"}
+
+  The function @{ML make_thm in Skip_Proof} however only works if 
+  the ``quick-and-dirty'' mode is switched on. 
+
+  Theorems also contain auxiliary data, such as the name of the theorem, its
+  kind, the names for cases and so on. This data is stored in a string-string
+  list and can be retrieved with the function @{ML_ind get_tags in
+  Thm}. Assume you prove the following lemma.
+*}
+
+lemma foo_data: 
+  shows "P \<Longrightarrow> P \<Longrightarrow> P" by assumption
+
+text {*
+  The auxiliary data of this lemma can be retrieved using the function 
+  @{ML_ind get_tags in Thm}. So far the the auxiliary data of this lemma is 
+
+  @{ML_response_fake [display,gray]
+  "Thm.get_tags @{thm foo_data}"
+  "[(\"name\", \"General.foo_data\"), (\"kind\", \"lemma\")]"}
+
+  consisting of a name and a kind.  When we store lemmas in the theorem database, 
+  we might want to explicitly extend this data by attaching case names to the 
+  two premises of the lemma.  This can be done with the function @{ML_ind name in Rule_Cases}
+  from the structure @{ML_struct Rule_Cases}.
+*}
+
+local_setup %gray {*
+  Local_Theory.note ((@{binding "foo_data'"}, []), 
+    [(Rule_Cases.name ["foo_case_one", "foo_case_two"] 
+       @{thm foo_data})]) #> snd *}
+
+text {*
+  The data of the theorem @{thm [source] foo_data'} is then as follows:
+
+  @{ML_response_fake [display,gray]
+  "Thm.get_tags @{thm foo_data'}"
+  "[(\"name\", \"General.foo_data'\"), (\"kind\", \"lemma\"), 
+ (\"case_names\", \"foo_case_one;foo_case_two\")]"}
+
+  You can observe the case names of this lemma on the user level when using 
+  the proof methods @{text cases} and @{text induct}. In the proof below
+*}
+
+lemma
+  shows "Q \<Longrightarrow> Q \<Longrightarrow> Q"
+proof (cases rule: foo_data')
+
+(*<*)oops(*>*)
+text_raw{*
+\begin{tabular}{@ {}l}
+\isacommand{print\_cases}\\
+@{text "> cases:"}\\
+@{text ">   foo_case_one:"}\\
+@{text ">     let \"?case\" = \"?P\""}\\
+@{text ">   foo_case_two:"}\\
+@{text ">     let \"?case\" = \"?P\""}
+\end{tabular}*}
+
+text {*
+  we can proceed by analysing the cases @{text "foo_case_one"} and 
+  @{text "foo_case_two"}. While if the theorem has no names, then
+  the cases have standard names @{text 1}, @{text 2} and so 
+  on. This can be seen in the proof below.
+*}
+
+lemma
+  shows "Q \<Longrightarrow> Q \<Longrightarrow> Q"
+proof (cases rule: foo_data)
+
+(*<*)oops(*>*)
+text_raw{*
+\begin{tabular}{@ {}l}
+\isacommand{print\_cases}\\
+@{text "> cases:"}\\
+@{text ">   1:"}\\
+@{text ">     let \"?case\" = \"?P\""}\\
+@{text ">   2:"}\\
+@{text ">     let \"?case\" = \"?P\""}
+\end{tabular}*}
+
+
+text {*
+  One great feature of Isabelle is its document preparation system, where
+  proved theorems can be quoted in documents referencing directly their
+  formalisation. This helps tremendously to minimise cut-and-paste errors. However,
+  sometimes the verbatim quoting is not what is wanted or what can be shown to
+  readers. For such situations Isabelle allows the installation of \emph{\index*{theorem 
+  styles}}. These are, roughly speaking, functions from terms to terms. The input 
+  term stands for the theorem to be presented; the output can be constructed to
+  ones wishes.  Let us, for example, assume we want to quote theorems without
+  leading @{text \<forall>}-quantifiers. For this we can implement the following function 
+  that strips off @{text "\<forall>"}s.
+*}
+
+ML %linenosgray{*fun strip_allq (Const (@{const_name "All"}, _) $ Abs body) = 
+      Term.dest_abs body |> snd |> strip_allq
+  | strip_allq (Const (@{const_name "Trueprop"}, _) $ t) = 
+      strip_allq t
+  | strip_allq t = t*}
+
+text {*
+  We use in Line 2 the function @{ML_ind dest_abs in Term} for deconstructing abstractions,
+  since this function deals correctly with potential name clashes. This function produces
+  a pair consisting of the variable and the body of the abstraction. We are only interested
+  in the body, which we feed into the recursive call. In Line 3 and 4, we also
+  have to explicitly strip of the outermost @{term Trueprop}-coercion. Now we can 
+  install this function as the theorem style named @{text "my_strip_allq"}. 
+*}
+
+setup %gray {*
+  Term_Style.setup "my_strip_allq" (Scan.succeed (K strip_allq)) 
+*}
+
+text {*
+  We can test this theorem style with the following theorem
+*}
+
+theorem style_test:
+  shows "\<forall>x y z. (x, x) = (y, z)" sorry
+
+text {*
+  Now printing out in a document the theorem @{thm [source] style_test} normally
+  using @{text "@{thm \<dots>}"} produces
+
+  \begin{isabelle}
+  @{text "@{thm style_test}"}\\
+  @{text ">"}~@{thm style_test}
+  \end{isabelle}
+
+  as expected. But with the theorem style @{text "@{thm (my_strip_allq) \<dots>}"} 
+  we obtain
+
+  \begin{isabelle}
+  @{text "@{thm (my_strip_allq) style_test}"}\\
+  @{text ">"}~@{thm (my_strip_allq) style_test}\\
+  \end{isabelle}
+  
+  without the leading quantifiers. We can improve this theorem style by explicitly 
+  giving a list of strings that should be used for the replacement of the
+  variables. For this we implement the function which takes a list of strings
+  and uses them as name in the outermost abstractions.
+*}
+
+ML{*fun rename_allq [] t = t
+  | rename_allq (x::xs) (Const (@{const_name "All"}, U) $ Abs (_, T, t)) = 
+      Const (@{const_name "All"}, U) $ Abs (x, T, rename_allq xs t)
+  | rename_allq xs (Const (@{const_name "Trueprop"}, U) $ t) =
+      rename_allq xs t
+  | rename_allq _ t = t*}
+
+text {*
+  We can now install a the modified theorem style as follows
+*}
+
+setup %gray {* let
+  val parser = Scan.repeat Args.name
+  fun action xs = K (rename_allq xs #> strip_allq)
+in
+  Term_Style.setup "my_strip_allq2" (parser >> action)
+end *}
+
+text {*
+  The parser reads a list of names. In the function @{text action} we first
+  call @{ML rename_allq} with the parsed list, then we call @{ML strip_allq}
+  on the resulting term. We can now suggest, for example, two variables for
+  stripping off the first two @{text \<forall>}-quantifiers.
+
+
+  \begin{isabelle}
+  @{text "@{thm (my_strip_allq2 x' x'') style_test}"}\\
+  @{text ">"}~@{thm (my_strip_allq2 x' x'') style_test}
+  \end{isabelle}
+
+  Such theorem styles allow one to print out theorems in documents formatted to
+  ones heart content. Next we explain theorem attributes, which is another
+  mechanism for dealing with theorems.
+
+  \begin{readmore}
+  Theorem styles are implemented in @{ML_file "Pure/Thy/term_style.ML"}.
+  \end{readmore}
+*}
+
+section {* Theorem Attributes\label{sec:attributes} *}
+
+text {*
+  Theorem attributes are @{text "[symmetric]"}, @{text "[THEN \<dots>]"}, @{text
+  "[simp]"} and so on. Such attributes are \emph{neither} tags \emph{nor} flags
+  annotated to theorems, but functions that do further processing of 
+  theorems. In particular, it is not possible to find out
+  what are all theorems that have a given attribute in common, unless of course
+  the function behind the attribute stores the theorems in a retrievable 
+  data structure. 
+
+  If you want to print out all currently known attributes a theorem can have, 
+  you can use the Isabelle command
+
+  \begin{isabelle}
+  \isacommand{print\_attributes}\\
+  @{text "> COMP:  direct composition with rules (no lifting)"}\\
+  @{text "> HOL.dest:  declaration of Classical destruction rule"}\\
+  @{text "> HOL.elim:  declaration of Classical elimination rule"}\\
+  @{text "> \<dots>"}
+  \end{isabelle}
+  
+  The theorem attributes fall roughly into two categories: the first category manipulates
+  theorems (for example @{text "[symmetric]"} and @{text "[THEN \<dots>]"}), and the second
+  stores theorems somewhere as data (for example @{text "[simp]"}, which adds
+  theorems to the current simpset).
+
+  To explain how to write your own attribute, let us start with an extremely simple 
+  version of the attribute @{text "[symmetric]"}. The purpose of this attribute is
+  to produce the ``symmetric'' version of an equation. The main function behind 
+  this attribute is
+*}
+
+ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*}
+
+text {* 
+  where the function @{ML_ind  rule_attribute in Thm} expects a function taking a 
+  context (which we ignore in the code above) and a theorem (@{text thm}), and 
+  returns another theorem (namely @{text thm} resolved with the theorem 
+  @{thm [source] sym}: @{thm sym[no_vars]}; the function @{ML_ind RS in Drule} 
+  is explained in Section~\ref{sec:simpletacs}). The function 
+  @{ML rule_attribute in Thm} then returns  an attribute.
+
+  Before we can use the attribute, we need to set it up. This can be done
+  using the Isabelle command \isacommand{attribute\_setup} as follows:
+*}
+
+attribute_setup %gray my_sym = 
+  {* Scan.succeed my_symmetric *} "applying the sym rule"
+
+text {*
+  Inside the @{text "\<verbopen> \<dots> \<verbclose>"}, we have to specify a parser
+  for the theorem attribute. Since the attribute does not expect any further 
+  arguments (unlike @{text "[THEN \<dots>]"}, for instance), we use the parser @{ML
+  Scan.succeed}. An example for the attribute @{text "[my_sym]"} is the proof
+*} 
+
+lemma test[my_sym]: "2 = Suc (Suc 0)" by simp
+
+text {*
+  which stores the theorem @{thm test} under the name @{thm [source] test}. You
+  can see this, if you query the lemma: 
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test"}\\
+  @{text "> "}~@{thm test}
+  \end{isabelle}
+
+  We can also use the attribute when referring to this theorem:
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test[my_sym]"}\\
+  @{text "> "}~@{thm test[my_sym]}
+  \end{isabelle}
+
+  An alternative for setting up an attribute is the function @{ML_ind  setup in Attrib}.
+  So instead of using \isacommand{attribute\_setup}, you can also set up the
+  attribute as follows:
+*}
+
+ML{*Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric)
+  "applying the sym rule" *}
+
+text {*
+  This gives a function from @{ML_type "theory -> theory"}, which
+  can be used for example with \isacommand{setup} or with
+  @{ML "Context.>> o Context.map_theory"}.\footnote{\bf FIXME: explain what happens here.}
+
+  As an example of a slightly more complicated theorem attribute, we implement 
+  our own version of @{text "[THEN \<dots>]"}. This attribute will take a list of theorems
+  as argument and resolve the theorem with this list (one theorem 
+  after another). The code for this attribute is
+*}
+
+ML{*fun MY_THEN thms = 
+  Thm.rule_attribute 
+    (fn _ => fn thm => fold (curry ((op RS) o swap)) thms thm)*}
+
+text {* 
+  where @{ML swap} swaps the components of a pair. The setup of this theorem
+  attribute uses the parser @{ML thms in Attrib}, which parses a list of
+  theorems. 
+*}
+
+attribute_setup %gray MY_THEN = {* Attrib.thms >> MY_THEN *} 
+  "resolving the list of theorems with the theorem"
+
+text {* 
+  You can, for example, use this theorem attribute to turn an equation into a 
+  meta-equation:
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test[MY_THEN eq_reflection]"}\\
+  @{text "> "}~@{thm test[MY_THEN eq_reflection]}
+  \end{isabelle}
+
+  If you need the symmetric version as a meta-equation, you can write
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test[MY_THEN sym eq_reflection]"}\\
+  @{text "> "}~@{thm test[MY_THEN sym eq_reflection]}
+  \end{isabelle}
+
+  It is also possible to combine different theorem attributes, as in:
+  
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test[my_sym, MY_THEN eq_reflection]"}\\
+  @{text "> "}~@{thm test[my_sym, MY_THEN eq_reflection]}
+  \end{isabelle}
+  
+  However, here also a weakness of the concept
+  of theorem attributes shows through: since theorem attributes can be
+  arbitrary functions, they do not commute in general. If you try
+
+  \begin{isabelle}
+  \isacommand{thm}~@{text "test[MY_THEN eq_reflection, my_sym]"}\\
+  @{text "> "}~@{text "exception THM 1 raised: RSN: no unifiers"}
+  \end{isabelle}
+
+  you get an exception indicating that the theorem @{thm [source] sym}
+  does not resolve with meta-equations. 
+
+  The purpose of @{ML_ind rule_attribute in Thm} is to directly manipulate
+  theorems.  Another usage of theorem attributes is to add and delete theorems
+  from stored data.  For example the theorem attribute @{text "[simp]"} adds
+  or deletes a theorem from the current simpset. For these applications, you
+  can use @{ML_ind declaration_attribute in Thm}. To illustrate this function,
+  let us introduce a theorem list.
+*}
+
+ML{*structure MyThms = Named_Thms
+  (val name = "attr_thms" 
+   val description = "Theorems for an Attribute") *}
+
+text {* 
+  We are going to modify this list by adding and deleting theorems.
+  For this we use the two functions @{ML MyThms.add_thm} and
+  @{ML MyThms.del_thm}. You can turn them into attributes 
+  with the code
+*}
+
+ML{*val my_add = Thm.declaration_attribute MyThms.add_thm
+val my_del = Thm.declaration_attribute MyThms.del_thm *}
+
+text {* 
+  and set up the attributes as follows
+*}
+
+attribute_setup %gray my_thms = {* Attrib.add_del my_add my_del *} 
+  "maintaining a list of my_thms" 
+
+text {*
+  The parser @{ML_ind  add_del in Attrib} is a predefined parser for 
+  adding and deleting lemmas. Now if you prove the next lemma 
+  and attach to it the attribute @{text "[my_thms]"}
+*}
+
+lemma trueI_2[my_thms]: "True" by simp
+
+text {*
+  then you can see it is added to the initially empty list.
+
+  @{ML_response_fake [display,gray]
+  "MyThms.get @{context}" 
+  "[\"True\"]"}
+
+  You can also add theorems using the command \isacommand{declare}.
+*}
+
+declare test[my_thms] trueI_2[my_thms add]
+
+text {*
+  With this attribute, the @{text "add"} operation is the default and does 
+  not need to be explicitly given. These three declarations will cause the 
+  theorem list to be updated as:
+
+  @{ML_response_fake [display,gray]
+  "MyThms.get @{context}"
+  "[\"True\", \"Suc (Suc 0) = 2\"]"}
+
+  The theorem @{thm [source] trueI_2} only appears once, since the 
+  function @{ML_ind  add_thm in Thm} tests for duplicates, before extending
+  the list. Deletion from the list works as follows:
+*}
+
+declare test[my_thms del]
+
+text {* After this, the theorem list is again: 
+
+  @{ML_response_fake [display,gray]
+  "MyThms.get @{context}"
+  "[\"True\"]"}
+
+  We used in this example two functions declared as @{ML_ind
+  declaration_attribute in Thm}, but there can be any number of them. We just
+  have to change the parser for reading the arguments accordingly.
+
+  \footnote{\bf FIXME What are: @{text "theory_attributes"}, @{text "proof_attributes"}?}
+
+  \begin{readmore}
+  FIXME: @{ML_file "Pure/more_thm.ML"}; parsers for attributes is in 
+  @{ML_file "Pure/Isar/attrib.ML"}...also explained in the chapter about
+  parsing.
+  \end{readmore}
+*}
+
+section {* Pretty-Printing\label{sec:pretty} *}
+
+text {*
+  So far we printed out only plain strings without any formatting except for
+  occasional explicit line breaks using @{text [quotes] "\\n"}. This is
+  sufficient for ``quick-and-dirty'' printouts. For something more
+  sophisticated, Isabelle includes an infrastructure for properly formatting
+  text. Most of its functions do not operate on @{ML_type string}s, but on
+  instances of the pretty type:
+
+  @{ML_type_ind [display, gray] "Pretty.T"}
+
+  The function @{ML str in Pretty} transforms a (plain) string into such a pretty 
+  type. For example
+
+  @{ML_response_fake [display,gray]
+  "Pretty.str \"test\"" "String (\"test\", 4)"}
+
+  where the result indicates that we transformed a string with length 4. Once
+  you have a pretty type, you can, for example, control where linebreaks may
+  occur in case the text wraps over a line, or with how much indentation a
+  text should be printed.  However, if you want to actually output the
+  formatted text, you have to transform the pretty type back into a @{ML_type
+  string}. This can be done with the function @{ML_ind  string_of in Pretty}. In what
+  follows we will use the following wrapper function for printing a pretty
+  type:
+*}
+
+ML{*fun pprint prt = tracing (Pretty.string_of prt)*}
+
+text {*
+  The point of the pretty-printing infrastructure is to give hints about how to
+  layout text and let Isabelle do the actual layout. Let us first explain
+  how you can insert places where a line break can occur. For this assume the
+  following function that replicates a string n times:
+*}
+
+ML{*fun rep n str = implode (replicate n str) *}
+
+text {*
+  and suppose we want to print out the string:
+*}
+
+ML{*val test_str = rep 8 "fooooooooooooooobaaaaaaaaaaaar "*}
+
+text {*
+  We deliberately chose a large string so that it spans over more than one line. 
+  If we print out the string using the usual ``quick-and-dirty'' method, then
+  we obtain the ugly output:
+
+@{ML_response_fake [display,gray]
+"tracing test_str"
+"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
+ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
+aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
+oooooooooooooobaaaaaaaaaaaar"}
+
+  We obtain the same if we just use the function @{ML pprint}.
+
+@{ML_response_fake [display,gray]
+"pprint (Pretty.str test_str)"
+"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
+ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
+aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
+oooooooooooooobaaaaaaaaaaaar"}
+
+  However by using pretty types you have the ability to indicate possible
+  linebreaks for example at each whitespace. You can achieve this with the
+  function @{ML_ind breaks in Pretty}, which expects a list of pretty types
+  and inserts a possible line break in between every two elements in this
+  list. To print this list of pretty types as a single string, we concatenate
+  them with the function @{ML_ind blk in Pretty} as follows:
+
+@{ML_response_fake [display,gray]
+"let
+  val ptrs = map Pretty.str (space_explode \" \" test_str)
+in
+  pprint (Pretty.blk (0, Pretty.breaks ptrs))
+end"
+"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
+fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
+
+  Here the layout of @{ML test_str} is much more pleasing to the 
+  eye. The @{ML "0"} in @{ML_ind  blk in Pretty} stands for no hanging 
+  indentation of the printed string. You can increase the indentation 
+  and obtain
+  
+@{ML_response_fake [display,gray]
+"let
+  val ptrs = map Pretty.str (space_explode \" \" test_str)
+in
+  pprint (Pretty.blk (3, Pretty.breaks ptrs))
+end"
+"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
+   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
+
+  where starting from the second line the indent is 3. If you want
+  that every line starts with the same indent, you can use the
+  function @{ML_ind  indent in Pretty} as follows:
+
+@{ML_response_fake [display,gray]
+"let
+  val ptrs = map Pretty.str (space_explode \" \" test_str)
+in
+  pprint (Pretty.indent 10 (Pretty.blk (0, Pretty.breaks ptrs)))
+end"
+"          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
+          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
+          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
+
+  If you want to print out a list of items separated by commas and 
+  have the linebreaks handled properly, you can use the function 
+  @{ML_ind  commas in Pretty}. For example
+
+@{ML_response_fake [display,gray]
+"let
+  val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
+in
+  pprint (Pretty.blk (0, Pretty.commas ptrs))
+end"
+"99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
+100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
+100016, 100017, 100018, 100019, 100020"}
+
+  where @{ML upto} generates a list of integers. You can print out this
+  list as a ``set'', that means enclosed inside @{text [quotes] "{"} and
+  @{text [quotes] "}"}, and separated by commas using the function
+  @{ML_ind  enum in Pretty}. For example
+*}
+
+text {*
+  
+@{ML_response_fake [display,gray]
+"let
+  val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
+in
+  pprint (Pretty.enum \",\" \"{\" \"}\" ptrs)
+end"
+"{99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
+  100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
+  100016, 100017, 100018, 100019, 100020}"}
+
+  As can be seen, this function prints out the ``set'' so that starting 
+  from the second, each new line has an indentation of 2.
+  
+  If you print out something that goes beyond the capabilities of the
+  standard functions, you can do relatively easily the formatting
+  yourself. Assume you want to print out a list of items where like in ``English''
+  the last two items are separated by @{text [quotes] "and"}. For this you can
+  write the function
+
+*}
+
+ML %linenosgray{*fun and_list [] = []
+  | and_list [x] = [x]
+  | and_list xs = 
+      let 
+        val (front, last) = split_last xs
+      in
+        (Pretty.commas front) @ 
+        [Pretty.brk 1, Pretty.str "and", Pretty.brk 1, last]
+      end *}
+
+text {*
+  where Line 7 prints the beginning of the list and Line
+  8 the last item. We have to use @{ML "Pretty.brk 1"} in order
+  to insert a space (of length 1) before the 
+  @{text [quotes] "and"}. This space is also a place where a line break 
+  can occur. We do the same after the @{text [quotes] "and"}. This gives you
+  for example
+
+@{ML_response_fake [display,gray]
+"let
+  val ptrs1 = map (Pretty.str o string_of_int) (1 upto 22)
+  val ptrs2 = map (Pretty.str o string_of_int) (10 upto 28)
+in
+  pprint (Pretty.blk (0, and_list ptrs1));
+  pprint (Pretty.blk (0, and_list ptrs2))
+end"
+"1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 
+and 22
+10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 and
+28"}
+
+  Next we like to pretty-print a term and its type. For this we use the
+  function @{text "tell_type"}.
+*}
+
+ML %linenosgray{*fun tell_type ctxt t = 
+let
+  fun pstr s = Pretty.breaks (map Pretty.str (space_explode " " s))
+  val ptrm = Pretty.quote (Syntax.pretty_term ctxt t)
+  val pty  = Pretty.quote (Syntax.pretty_typ ctxt (fastype_of t))
+in
+  pprint (Pretty.blk (0, 
+    (pstr "The term " @ [ptrm] @ pstr " has type " 
+      @ [pty, Pretty.str "."])))
+end*}
+
+text {*
+  In Line 3 we define a function that inserts possible linebreaks in places
+  where a space is. In Lines 4 and 5 we pretty-print the term and its type
+  using the functions @{ML_ind  pretty_term in Syntax} and @{ML_ind 
+  pretty_typ in Syntax}. We also use the function @{ML_ind quote in
+  Pretty} in order to enclose the term and type inside quotation marks. In
+  Line 9 we add a period right after the type without the possibility of a
+  line break, because we do not want that a line break occurs there.
+  Now you can write
+
+  @{ML_response_fake [display,gray]
+  "tell_type @{context} @{term \"min (Suc 0)\"}"
+  "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."}
+  
+  To see the proper line breaking, you can try out the function on a bigger term 
+  and type. For example:
+
+  @{ML_response_fake [display,gray]
+  "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}"
+  "The term \"op = (op = (op = (op = (op = op =))))\" has type 
+\"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."}
+
+  The function @{ML_ind big_list in Pretty} helps with printing long lists.
+  It is used for example in the command \isacommand{print\_theorems}. An
+  example is as follows.
+
+  @{ML_response_fake [display,gray]
+  "let
+  val pstrs = map (Pretty.str o string_of_int) (4 upto 10)
+in
+  pprint (Pretty.big_list \"header\" pstrs)
+end"
+  "header
+  4
+  5
+  6
+  7
+  8
+  9
+  10"}
+
+  Like @{ML blk in Pretty}, the function @{ML_ind chunks in Pretty} prints out 
+  a list of items, but automatically inserts forced breaks between each item.
+  Compare
+
+  @{ML_response_fake [display,gray]
+  "let
+  val a_and_b = [Pretty.str \"a\", Pretty.str \"b\"]
+in
+  pprint (Pretty.blk (0, a_and_b));
+  pprint (Pretty.chunks a_and_b)
+end"
+"ab
+a
+b"}
+  
+  \footnote{\bf FIXME: What happens with printing big formulae?}
+
+  
+
+  \begin{readmore}
+  The general infrastructure for pretty-printing is implemented in the file
+  @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"}
+  contains pretty-printing functions for terms, types, theorems and so on.
+  
+  @{ML_file "Pure/General/markup.ML"}
+  \end{readmore}
+*}
+
+(*
+text {*
+  printing into the goal buffer as part of the proof state
+*}
+
+text {* writing into the goal buffer *}
+
+ML {* fun my_hook interactive state =
+         (interactive ? Proof.goal_message (fn () => Pretty.str  
+"foo")) state
+*}
+
+setup %gray {* Context.theory_map (Specification.add_theorem_hook my_hook) *}
+
+lemma "False"
+oops
+*)
+
+(*
+ML {*
+fun setmp_show_all_types f =
+   setmp show_all_types
+         (! show_types orelse ! show_sorts orelse ! show_all_types) f;
+
+val ctxt = @{context};
+val t1 = @{term "undefined::nat"};
+val t2 = @{term "Suc y"};
+val pty =        Pretty.block (Pretty.breaks
+             [(setmp show_question_marks false o setmp_show_all_types)
+                  (Syntax.pretty_term ctxt) t1,
+              Pretty.str "=", Syntax.pretty_term ctxt t2]);
+pty |> Pretty.string_of  
+*}
+
+text {* the infrastructure of Syntax-pretty-term makes sure it is printed nicely  *}
+
+
+ML {* Pretty.mark Markup.hilite (Pretty.str "foo") |> Pretty.string_of  |> tracing *}
+ML {* (Pretty.str "bar") |> Pretty.string_of |> tracing *}
+*)
+
+section {* Summary *}
+
+text {*
+  \begin{conventions}
+  \begin{itemize}
+  \item Start with a proper context and then pass it around 
+  through all your functions.
+  \end{itemize}
+  \end{conventions}
+*}
+
+end
--- a/ProgTutorial/General.thy	Thu Nov 19 14:11:50 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2571 +0,0 @@
-theory General
-imports Base FirstSteps
-begin
-
-(*<*)
-setup{*
-open_file_with_prelude 
-  "General_Code.thy"
-  ["theory General", "imports Base FirstSteps", "begin"]
-*}
-(*>*)
-
-
-chapter {* Isabelle Essentials *}
-
-text {*
-  Isabelle is build around a few central ideas. One central idea is the
-  LCF-approach to theorem proving where there is a small trusted core and
-  everything else is build on top of this trusted core 
-  \cite{GordonMilnerWadsworth79}. The fundamental data
-  structures involved in this core are certified terms and certified types, 
-  as well as theorems.
-*}
-
-
-section {* Terms and Types *}
-
-text {*
-  In Isabelle, there are certified terms and uncertified terms (respectively types). 
-  Uncertified terms are often just called terms. One way to construct them is by 
-  using the antiquotation \mbox{@{text "@{term \<dots>}"}}. For example
-
-  @{ML_response [display,gray] 
-"@{term \"(a::nat) + b = c\"}" 
-"Const (\"op =\", \<dots>) $ 
-  (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
-
-  constructs the term @{term "(a::nat) + b = c"}. The resulting term is printed using 
-  the internal representation corresponding to the datatype @{ML_type_ind "term"}, 
-  which is defined as follows: 
-*}  
-
-ML_val %linenosgray{*datatype term =
-  Const of string * typ 
-| Free of string * typ 
-| Var of indexname * typ 
-| Bound of int 
-| Abs of string * typ * term 
-| $ of term * term *}
-
-text {*
-  This datatype implements Church-style lambda-terms, where types are
-  explicitly recorded in variables, constants and abstractions.  As can be
-  seen in Line 5, terms use the usual de Bruijn index mechanism for
-  representing bound variables.  For example in
-
-  @{ML_response_fake [display, gray]
-  "@{term \"\<lambda>x y. x y\"}"
-  "Abs (\"x\", \"'a \<Rightarrow> 'b\", Abs (\"y\", \"'a\", Bound 1 $ Bound 0))"}
-
-  the indices refer to the number of Abstractions (@{ML Abs}) that we need to
-  skip until we hit the @{ML Abs} that binds the corresponding
-  variable. Constructing a term with dangling de Bruijn indices is possible,
-  but will be flagged as ill-formed when you try to typecheck or certify it
-  (see Section~\ref{sec:typechecking}). Note that the names of bound variables
-  are kept at abstractions for printing purposes, and so should be treated
-  only as ``comments''.  Application in Isabelle is realised with the
-  term-constructor @{ML $}.
-
-  Isabelle makes a distinction between \emph{free} variables (term-constructor
-  @{ML Free} and written on the user level in blue colour) and
-  \emph{schematic} variables (term-constructor @{ML Var} and written with a
-  leading question mark). Consider the following two examples
-  
-  @{ML_response_fake [display, gray]
-"let
-  val v1 = Var ((\"x\", 3), @{typ bool})
-  val v2 = Var ((\"x1\", 3), @{typ bool})
-  val v3 = Free (\"x\", @{typ bool})
-in
-  string_of_terms @{context} [v1, v2, v3]
-  |> tracing
-end"
-"?x3, ?x1.3, x"}
-
-  When constructing terms, you are usually concerned with free variables (as
-  mentioned earlier, you cannot construct schematic variables using the
-  antiquotation @{text "@{term \<dots>}"}). If you deal with theorems, you have to,
-  however, observe the distinction. The reason is that only schematic
-  variables can be instantiated with terms when a theorem is applied. A
-  similar distinction between free and schematic variables holds for types
-  (see below).
-
-  \begin{readmore}
-  Terms and types are described in detail in \isccite{sec:terms}. Their
-  definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}.
-  For constructing terms involving HOL constants, many helper functions are defined
-  in @{ML_file "HOL/Tools/hologic.ML"}.
-  \end{readmore}
-  
-  Constructing terms via antiquotations has the advantage that only typable
-  terms can be constructed. For example
-
-  @{ML_response_fake_both [display,gray]
-  "@{term \"x x\"}"
-  "Type unification failed: Occurs check!"}
-
-  raises a typing error, while it perfectly ok to construct the term
-
-  @{ML_response_fake [display,gray] 
-"let
-  val omega = Free (\"x\", @{typ \"nat \<Rightarrow> nat\"}) $ Free (\"x\", @{typ nat})
-in 
-  tracing (string_of_term @{context} omega)
-end"
-  "x x"}
-
-  with the raw ML-constructors.
-  
-  Sometimes the internal representation of terms can be surprisingly different
-  from what you see at the user-level, because the layers of
-  parsing/type-checking/pretty printing can be quite elaborate. 
-
-  \begin{exercise}
-  Look at the internal term representation of the following terms, and
-  find out why they are represented like this:
-
-  \begin{itemize}
-  \item @{term "case x of 0 \<Rightarrow> 0 | Suc y \<Rightarrow> y"}  
-  \item @{term "\<lambda>(x,y). P y x"}  
-  \item @{term "{ [x::int] | x. x \<le> -2 }"}  
-  \end{itemize}
-
-  Hint: The third term is already quite big, and the pretty printer
-  may omit parts of it by default. If you want to see all of it, you
-  can use the following ML-function to set the printing depth to a higher 
-  value:
-
-  @{ML [display,gray] "print_depth 50"}
-  \end{exercise}
-
-  The antiquotation @{text "@{prop \<dots>}"} constructs terms by inserting the 
-  usually invisible @{text "Trueprop"}-coercions whenever necessary. 
-  Consider for example the pairs
-
-@{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" 
-"(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>),
- Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"}
- 
-  where a coercion is inserted in the second component and 
-
-  @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" 
-  "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, 
- Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"}
-
-  where it is not (since it is already constructed by a meta-implication). 
-  The purpose of the @{text "Trueprop"}-coercion is to embed formulae of
-  an object logic, for example HOL, into the meta-logic of Isabelle. The coercion
-  is needed whenever a term is constructed that will be proved as a theorem. 
-
-  As already seen above, types can be constructed using the antiquotation 
-  @{text "@{typ \<dots>}"}. For example:
-
-  @{ML_response_fake [display,gray] "@{typ \"bool \<Rightarrow> nat\"}" "bool \<Rightarrow> nat"}
-
-  The corresponding datatype is
-*}
-  
-ML_val{*datatype typ =
-  Type  of string * typ list 
-| TFree of string * sort 
-| TVar  of indexname * sort *}
-
-text {*
-  Like with terms, there is the distinction between free type
-  variables (term-constructor @{ML "TFree"}) and schematic
-  type variables (term-constructor @{ML "TVar"} and printed with
-  a leading question mark). A type constant,
-  like @{typ "int"} or @{typ bool}, are types with an empty list
-  of argument types. However, it needs a bit of effort to show an
-  example, because Isabelle always pretty prints types (unlike terms).
-  Using just the antiquotation @{text "@{typ \"bool\"}"} we only see
-
-  @{ML_response [display, gray]
-  "@{typ \"bool\"}"
-  "bool"}
-
-  that is the pretty printed version of @{text "bool"}. However, in PolyML
-  (version 5.3) it is easy to install your own pretty printer. With the
-  function below we mimic the behaviour of the usual pretty printer for
-  datatypes (it uses pretty-printing functions which will be explained in more
-  detail in Section~\ref{sec:pretty}).
-*}
-
-ML{*local
-  fun pp_pair (x, y) = Pretty.list "(" ")" [x, y]
-  fun pp_list xs = Pretty.list "[" "]" xs
-  fun pp_str s   = Pretty.str s
-  fun pp_qstr s  = Pretty.quote (pp_str s)
-  fun pp_int i   = pp_str (string_of_int i)
-  fun pp_sort S  = pp_list (map pp_qstr S)
-  fun pp_constr a args = Pretty.block [pp_str a, Pretty.brk 1, args]
-in
-fun raw_pp_typ (TVar ((a, i), S)) = 
-      pp_constr "TVar" (pp_pair (pp_pair (pp_qstr a, pp_int i), pp_sort S))
-  | raw_pp_typ (TFree (a, S)) = 
-      pp_constr "TFree" (pp_pair (pp_qstr a, pp_sort S))
-  | raw_pp_typ (Type (a, tys)) = 
-      pp_constr "Type" (pp_pair (pp_qstr a, pp_list (map raw_pp_typ tys)))
-end*}
-
-text {*
-  We can install this pretty printer with the function 
-  @{ML_ind addPrettyPrinter in PolyML} as follows.
-*}
-
-ML{*PolyML.addPrettyPrinter 
-  (fn _ => fn _ => ml_pretty o Pretty.to_ML o raw_pp_typ)*}
-
-text {*
-  Now the type bool is printed out in full detail.
-
-  @{ML_response [display,gray]
-  "@{typ \"bool\"}"
-  "Type (\"bool\", [])"}
-
-  When printing out a list-type
-  
-  @{ML_response [display,gray]
-  "@{typ \"'a list\"}"
-  "Type (\"List.list\", [TFree (\"'a\", [\"HOL.type\"])])"}
-
-  we can see the full name of the type is actually @{text "List.list"}, indicating
-  that it is defined in the theory @{text "List"}. However, one has to be 
-  careful with names of types, because even if
-  @{text "fun"}, @{text "bool"} and @{text "nat"} are defined in the 
-  theories @{text "HOL"} and @{text "Nat"}, respectively, they are 
-  still represented by their simple name.
-
-   @{ML_response [display,gray]
-  "@{typ \"bool \<Rightarrow> nat\"}"
-  "Type (\"fun\", [Type (\"bool\", []), Type (\"nat\", [])])"}
-
-  We can restore the usual behaviour of Isabelle's pretty printer
-  with the code
-*}
-
-ML{*PolyML.addPrettyPrinter 
-  (fn _ => fn _ => ml_pretty o Pretty.to_ML o Proof_Display.pp_typ Pure.thy)*}
-
-text {*
-  After that the types for booleans, lists and so on are printed out again 
-  the standard Isabelle way.
-
-  @{ML_response_fake [display, gray]
-  "@{typ \"bool\"};
-@{typ \"'a list\"}"
-  "\"bool\"
-\"'a List.list\""}
-
-  \begin{readmore}
-  Types are described in detail in \isccite{sec:types}. Their
-  definition and many useful operations are implemented 
-  in @{ML_file "Pure/type.ML"}.
-  \end{readmore}
-*}
-
-section {* Constructing Terms and Types Manually\label{sec:terms_types_manually} *} 
-
-text {*
-  While antiquotations are very convenient for constructing terms, they can
-  only construct fixed terms (remember they are ``linked'' at compile-time).
-  However, you often need to construct terms manually. For example, a
-  function that returns the implication @{text "\<And>(x::nat). P x \<Longrightarrow> Q x"} taking
-  @{term P} and @{term Q} as arguments can only be written as:
-
-*}
-
-ML{*fun make_imp P Q =
-let
-  val x = Free ("x", @{typ nat})
-in 
-  Logic.all x (Logic.mk_implies (P $ x, Q $ x))
-end *}
-
-text {*
-  The reason is that you cannot pass the arguments @{term P} and @{term Q} 
-  into an antiquotation.\footnote{At least not at the moment.} For example 
-  the following does \emph{not} work.
-*}
-
-ML{*fun make_wrong_imp P Q = @{prop "\<And>(x::nat). P x \<Longrightarrow> Q x"} *}
-
-text {*
-  To see this, apply @{text "@{term S}"} and @{text "@{term T}"} 
-  to both functions. With @{ML make_imp} you obtain the intended term involving 
-  the given arguments
-
-  @{ML_response [display,gray] "make_imp @{term S} @{term T}" 
-"Const \<dots> $ 
-  Abs (\"x\", Type (\"nat\",[]),
-    Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ (Free (\"T\",\<dots>) $ \<dots>))"}
-
-  whereas with @{ML make_wrong_imp} you obtain a term involving the @{term "P"} 
-  and @{text "Q"} from the antiquotation.
-
-  @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T}" 
-"Const \<dots> $ 
-  Abs (\"x\", \<dots>,
-    Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ 
-                (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"}
-
-  There are a number of handy functions that are frequently used for
-  constructing terms. One is the function @{ML_ind list_comb in Term}, which
-  takes as argument a term and a list of terms, and produces as output the
-  term list applied to the term. For example
-
-
-@{ML_response_fake [display,gray]
-"let
-  val trm = @{term \"P::nat\"}
-  val args = [@{term \"True\"}, @{term \"False\"}]
-in
-  list_comb (trm, args)
-end"
-"Free (\"P\", \"nat\") $ Const (\"True\", \"bool\") $ Const (\"False\", \"bool\")"}
-
-  Another handy function is @{ML_ind lambda in Term}, which abstracts a variable 
-  in a term. For example
-
-  @{ML_response_fake [display,gray]
-"let
-  val x_nat = @{term \"x::nat\"}
-  val trm = @{term \"(P::nat \<Rightarrow> bool) x\"}
-in
-  lambda x_nat trm
-end"
-  "Abs (\"x\", \"nat\", Free (\"P\", \"bool \<Rightarrow> bool\") $ Bound 0)"}
-
-  In this example, @{ML lambda} produces a de Bruijn index (i.e.~@{ML "Bound 0"}), 
-  and an abstraction, where it also records the type of the abstracted
-  variable and for printing purposes also its name.  Note that because of the
-  typing annotation on @{text "P"}, the variable @{text "x"} in @{text "P x"}
-  is of the same type as the abstracted variable. If it is of different type,
-  as in
-
-  @{ML_response_fake [display,gray]
-"let
-  val x_int = @{term \"x::int\"}
-  val trm = @{term \"(P::nat \<Rightarrow> bool) x\"}
-in
-  lambda x_int trm
-end"
-  "Abs (\"x\", \"int\", Free (\"P\", \"nat \<Rightarrow> bool\") $ Free (\"x\", \"nat\"))"}
-
-  then the variable @{text "Free (\"x\", \"int\")"} is \emph{not} abstracted. 
-  This is a fundamental principle
-  of Church-style typing, where variables with the same name still differ, if they 
-  have different type.
-
-  There is also the function @{ML_ind subst_free in Term} with which terms can be
-  replaced by other terms. For example below, we will replace in @{term
-  "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0 x"} the subterm @{term "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0"} by
-  @{term y}, and @{term x} by @{term True}.
-
-  @{ML_response_fake [display,gray]
-"let
-  val sub1 = (@{term \"(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0\"}, @{term \"y::nat \<Rightarrow> nat\"})
-  val sub2 = (@{term \"x::nat\"}, @{term \"True\"})
-  val trm = @{term \"((f::nat \<Rightarrow> nat \<Rightarrow> nat) 0) x\"}
-in
-  subst_free [sub1, sub2] trm
-end"
-  "Free (\"y\", \"nat \<Rightarrow> nat\") $ Const (\"True\", \"bool\")"}
-
-  As can be seen, @{ML subst_free} does not take typability into account.
-  However it takes alpha-equivalence into account:
-
-  @{ML_response_fake [display, gray]
-"let
-  val sub = (@{term \"(\<lambda>y::nat. y)\"}, @{term \"x::nat\"})
-  val trm = @{term \"(\<lambda>x::nat. x)\"}
-in
-  subst_free [sub] trm
-end"
-  "Free (\"x\", \"nat\")"}
-
-  Similarly the function @{ML_ind subst_bounds in Term}, replaces lose bound 
-  variables with terms. To see how this function works, let us implement a
-  function that strips off the outermost quantifiers in a term.
-*}
-
-ML{*fun strip_alls t =
-let 
-  fun aux (x, T, t) = strip_alls t |>> cons (Free (x, T))
-in
-  case t of
-    Const ("All", _) $ Abs body => aux body
-  | _ => ([], t)
-end*}
-
-text {*
-  The function returns a pair consisting of the stripped off variables and
-  the body of the universal quantification. For example
-
-  @{ML_response_fake [display, gray]
-  "strip_alls @{term \"\<forall>x y. x = (y::bool)\"}"
-"([Free (\"x\", \"bool\"), Free (\"y\", \"bool\")],
-  Const (\"op =\", \<dots>) $ Bound 1 $ Bound 0)"}
-
-  After calling @{ML strip_alls}, you obtain a term with lose bound variables. With
-  the function @{ML subst_bounds}, you can replace these lose @{ML_ind 
-  Bound in Term}s with the stripped off variables.
-
-  @{ML_response_fake [display, gray, linenos]
-  "let
-  val (vrs, trm) = strip_alls @{term \"\<forall>x y. x = (y::bool)\"}
-in 
-  subst_bounds (rev vrs, trm) 
-  |> string_of_term @{context}
-  |> tracing
-end"
-  "x = y"}
-
-  Note that in Line 4 we had to reverse the list of variables that @{ML
-  strip_alls} returned. The reason is that the head of the list the function
-  @{ML subst_bounds} takes is the replacement for @{ML "Bound 0"}, the next
-  element for @{ML "Bound 1"} and so on. 
-
-  Notice also that this function might introduce name clashes, since we
-  substitute just a variable with the name recorded in an abstraction. This
-  name is by no means unique. If clashes need to be avoided, then we should
-  use the function @{ML_ind dest_abs in Term}, which returns the body where
-  the lose de Bruijn index is replaced by a unique free variable. For example
-
-
-  @{ML_response_fake [display,gray]
-  "let
-  val body = Bound 0 $ Free (\"x\", @{typ nat})
-in
-  Term.dest_abs (\"x\", @{typ \"nat \<Rightarrow> bool\"}, body)
-end"
-  "(\"xa\", Free (\"xa\", \"nat \<Rightarrow> bool\") $ Free (\"x\", \"nat\"))"}
-
-  There are also many convenient functions that construct specific HOL-terms
-  in the structure @{ML_struct HOLogic}. For
-  example @{ML_ind mk_eq in HOLogic} constructs an equality out of two terms.
-  The types needed in this equality are calculated from the type of the
-  arguments. For example
-
-@{ML_response_fake [gray,display]
-"let
-  val eq = HOLogic.mk_eq (@{term \"True\"}, @{term \"False\"})
-in
-  string_of_term @{context} eq
-  |> tracing
-end"
-  "True = False"}
-*}
-
-text {*
-  \begin{readmore}
-  There are many functions in @{ML_file "Pure/term.ML"}, @{ML_file
-  "Pure/logic.ML"} and @{ML_file "HOL/Tools/hologic.ML"} that make manual
-  constructions of terms and types easier.
-  \end{readmore}
-
-  When constructing terms manually, there are a few subtle issues with
-  constants. They usually crop up when pattern matching terms or types, or
-  when constructing them. While it is perfectly ok to write the function
-  @{text is_true} as follows
-*}
-
-ML{*fun is_true @{term True} = true
-  | is_true _ = false*}
-
-text {*
-  this does not work for picking out @{text "\<forall>"}-quantified terms. Because
-  the function 
-*}
-
-ML{*fun is_all (@{term All} $ _) = true
-  | is_all _ = false*}
-
-text {* 
-  will not correctly match the formula @{prop[source] "\<forall>x::nat. P x"}: 
-
-  @{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "false"}
-
-  The problem is that the @{text "@term"}-antiquotation in the pattern 
-  fixes the type of the constant @{term "All"} to be @{typ "('a \<Rightarrow> bool) \<Rightarrow> bool"} for 
-  an arbitrary, but fixed type @{typ "'a"}. A properly working alternative 
-  for this function is
-*}
-
-ML{*fun is_all (Const ("All", _) $ _) = true
-  | is_all _ = false*}
-
-text {* 
-  because now
-
-@{ML_response [display,gray] "is_all @{term \"\<forall>x::nat. P x\"}" "true"}
-
-  matches correctly (the first wildcard in the pattern matches any type and the
-  second any term).
-
-  However there is still a problem: consider the similar function that
-  attempts to pick out @{text "Nil"}-terms:
-*}
-
-ML{*fun is_nil (Const ("Nil", _)) = true
-  | is_nil _ = false *}
-
-text {* 
-  Unfortunately, also this function does \emph{not} work as expected, since
-
-  @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"}
-
-  The problem is that on the ML-level the name of a constant is more
-  subtle than you might expect. The function @{ML is_all} worked correctly,
-  because @{term "All"} is such a fundamental constant, which can be referenced
-  by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at
-
-  @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"}
-
-  the name of the constant @{text "Nil"} depends on the theory in which the
-  term constructor is defined (@{text "List"}) and also in which datatype
-  (@{text "list"}). Even worse, some constants have a name involving
-  type-classes. Consider for example the constants for @{term "zero"} and
-  \mbox{@{text "(op *)"}}:
-
-  @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"(op *)\"})" 
- "(Const (\"HOL.zero_class.zero\", \<dots>), 
- Const (\"HOL.times_class.times\", \<dots>))"}
-
-  While you could use the complete name, for example 
-  @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or
-  matching against @{text "Nil"}, this would make the code rather brittle. 
-  The reason is that the theory and the name of the datatype can easily change. 
-  To make the code more robust, it is better to use the antiquotation 
-  @{text "@{const_name \<dots>}"}. With this antiquotation you can harness the 
-  variable parts of the constant's name. Therefore a function for 
-  matching against constants that have a polymorphic type should 
-  be written as follows.
-*}
-
-ML{*fun is_nil_or_all (Const (@{const_name "Nil"}, _)) = true
-  | is_nil_or_all (Const (@{const_name "All"}, _) $ _) = true
-  | is_nil_or_all _ = false *}
-
-text {*
-  The antiquotation for properly referencing type constants is @{text "@{type_name \<dots>}"}.
-  For example
-
-  @{ML_response [display,gray]
-  "@{type_name \"list\"}" "\"List.list\""}
-
-  \footnote{\bf FIXME: Explain the following better; maybe put in a separate
-  section and link with the comment in the antiquotation section.}
-
-  Occasionally you have to calculate what the ``base'' name of a given
-  constant is. For this you can use the function @{ML_ind "Sign.extern_const"} or
-  @{ML_ind  Long_Name.base_name}. For example:
-
-  @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""}
-
-  The difference between both functions is that @{ML extern_const in Sign} returns
-  the smallest name that is still unique, whereas @{ML base_name in Long_Name} always
-  strips off all qualifiers.
-
-  \begin{readmore}
-  Functions about naming are implemented in @{ML_file "Pure/General/name_space.ML"};
-  functions about signatures in @{ML_file "Pure/sign.ML"}.
-  \end{readmore}
-
-  Although types of terms can often be inferred, there are many
-  situations where you need to construct types manually, especially  
-  when defining constants. For example the function returning a function 
-  type is as follows:
-
-*} 
-
-ML{*fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2]) *}
-
-text {* This can be equally written with the combinator @{ML_ind "-->" in Term} as: *}
-
-ML{*fun make_fun_type ty1 ty2 = ty1 --> ty2 *}
-
-text {*
-  If you want to construct a function type with more than one argument
-  type, then you can use @{ML_ind "--->" in Term}.
-*}
-
-ML{*fun make_fun_types tys ty = tys ---> ty *}
-
-text {*
-  A handy function for manipulating terms is @{ML_ind map_types in Term}: it takes a 
-  function and applies it to every type in a term. You can, for example,
-  change every @{typ nat} in a term into an @{typ int} using the function:
-*}
-
-ML{*fun nat_to_int ty =
-  (case ty of
-     @{typ nat} => @{typ int}
-   | Type (s, tys) => Type (s, map nat_to_int tys)
-   | _ => ty)*}
-
-text {*
-  Here is an example:
-
-@{ML_response_fake [display,gray] 
-"map_types nat_to_int @{term \"a = (1::nat)\"}" 
-"Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\")
-           $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"}
-
-  If you want to obtain the list of free type-variables of a term, you
-  can use the function @{ML_ind  add_tfrees in Term} 
-  (similarly @{ML_ind  add_tvars in Term} for the schematic type-variables). 
-  One would expect that such functions
-  take a term as input and return a list of types. But their type is actually 
-
-  @{text[display] "Term.term -> (string * Term.sort) list -> (string * Term.sort) list"}
-
-  that is they take, besides a term, also a list of type-variables as input. 
-  So in order to obtain the list of type-variables of a term you have to 
-  call them as follows
-
-  @{ML_response [gray,display]
-  "Term.add_tfrees @{term \"(a, b)\"} []"
-  "[(\"'b\", [\"HOL.type\"]), (\"'a\", [\"HOL.type\"])]"}
-
-  The reason for this definition is that @{ML add_tfrees in Term} can
-  be easily folded over a list of terms. Similarly for all functions
-  named @{text "add_*"} in @{ML_file "Pure/term.ML"}.
-
-  \begin{exercise}\label{fun:revsum}
-  Write a function @{text "rev_sum : term -> term"} that takes a
-  term of the form @{text "t\<^isub>1 + t\<^isub>2 + \<dots> + t\<^isub>n"} (whereby @{text "n"} might be one)
-  and returns the reversed sum @{text "t\<^isub>n + \<dots> + t\<^isub>2 + t\<^isub>1"}. Assume
-  the @{text "t\<^isub>i"} can be arbitrary expressions and also note that @{text "+"} 
-  associates to the left. Try your function on some examples. 
-  \end{exercise}
-
-  \begin{exercise}\label{fun:makesum}
-  Write a function that takes two terms representing natural numbers
-  in unary notation (like @{term "Suc (Suc (Suc 0))"}), and produces the
-  number representing their sum.
-  \end{exercise}
-
-  \begin{exercise}\label{ex:debruijn}
-  Implement the function, which we below name deBruijn, that depends on a natural
-  number n$>$0 and constructs terms of the form:
-  
-  \begin{center}
-  \begin{tabular}{r@ {\hspace{2mm}}c@ {\hspace{2mm}}l}
-  {\it rhs n} & $\dn$ & {\large$\bigwedge$}{\it i=1\ldots n.  P\,i}\\
-  {\it lhs n} & $\dn$ & {\large$\bigwedge$}{\it i=1\ldots n. P\,i = P (i + 1 mod n)}
-                        $\longrightarrow$ {\it rhs n}\\
-  {\it deBruijn n} & $\dn$ & {\it lhs n} $\longrightarrow$ {\it rhs n}\\
-  \end{tabular}
-  \end{center}
-
-  This function returns for n=3 the term
-
-  \begin{center}
-  \begin{tabular}{l}
-  (P 1 = P 2 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\wedge$\\
-  (P 2 = P 3 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\wedge$\\ 
-  (P 3 = P 1 $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3) $\longrightarrow$ P 1 $\wedge$ P 2 $\wedge$ P 3
-  \end{tabular}
-  \end{center}
-
-  Make sure you use the functions defined in @{ML_file "HOL/Tools/hologic.ML"}
-  for constructing the terms for the logical connectives.\footnote{Thanks to Roy
-  Dyckhoff for suggesting this exercise and working out the details.} 
-  \end{exercise}
-*}
-
-section {* Unification and Matching *}
-
-text {* 
-  As seen earlier, Isabelle's terms and types may contain schematic term variables
-  (term-constructor @{ML Var}) and schematic type variables (term-constructor
-  @{ML TVar}). These variables stand for unknown entities, which can be made
-  more concrete by instantiations. Such instantiations might be a result of
-  unification or matching. While in case of types, unification and matching is
-  relatively straightforward, in case of terms the algorithms are
-  substantially more complicated, because terms need higher-order versions of
-  the unification and matching algorithms. Below we shall use the
-  antiquotations @{text "@{typ_pat \<dots>}"} and @{text "@{term_pat \<dots>}"} from
-  Section~\ref{sec:antiquote} in order to construct examples involving
-  schematic variables.
-
-  Let us begin with describing the unification and matching function for
-  types.  Both return type environments (ML-type @{ML_type "Type.tyenv"})
-  which map schematic type variables to types and sorts. Below we use the
-  function @{ML_ind typ_unify in Sign} from the structure @{ML_struct Sign}
-  for unifying the types @{text "?'a * ?'b"} and @{text "?'b list *
-  nat"}. This will produce the mapping, or type environment, @{text "[?'a :=
-  ?'b list, ?'b := nat]"}.
-*}
-
-ML %linenosgray{*val (tyenv_unif, _) = let
-  val ty1 = @{typ_pat "?'a * ?'b"}
-  val ty2 = @{typ_pat "?'b list * nat"}
-in
-  Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) 
-end*}
-
-text {* 
-  The environment @{ML_ind "Vartab.empty"} in line 5 stands for the empty type
-  environment, which is needed for starting the unification without any
-  (pre)instantiations. The @{text 0} is an integer index that will be explained
-  below. In case of failure @{ML typ_unify in Sign} will throw the exception
-  @{text TUNIFY}.  We can print out the resulting type environment bound to 
-  @{ML tyenv_unif} with the built-in function @{ML_ind dest in Vartab} from the
-  structure @{ML_struct Vartab}.
-
-  @{ML_response_fake [display,gray]
-  "Vartab.dest tyenv_unif"
-  "[((\"'a\", 0), ([\"HOL.type\"], \"?'b List.list\")), 
- ((\"'b\", 0), ([\"HOL.type\"], \"nat\"))]"} 
-*}
-
-text_raw {*
-  \begin{figure}[t]
-  \begin{minipage}{\textwidth}
-  \begin{isabelle}*}
-ML{*fun pretty_helper aux env =
-  env |> Vartab.dest  
-      |> map ((fn (s1, s2) => s1 ^ " := " ^ s2) o aux) 
-      |> commas 
-      |> enclose "[" "]" 
-      |> tracing
-
-fun pretty_tyenv ctxt tyenv =
-let
-  fun get_typs (v, (s, T)) = (TVar (v, s), T)
-  val print = pairself (Syntax.string_of_typ ctxt)
-in 
-  pretty_helper (print o get_typs) tyenv
-end*}
-text_raw {*
-  \end{isabelle}
-  \end{minipage}
-  \caption{A pretty printing function for type environments, which are 
-  produced by unification and matching.\label{fig:prettyenv}}
-  \end{figure}
-*}
-
-text {*
-  The first components in this list stand for the schematic type variables and
-  the second are the associated sorts and types. In this example the sort is
-  the default sort @{text "HOL.type"}. Instead of @{ML "Vartab.dest"}, we will
-  use in what follows our own pretty-printing function from
-  Figure~\ref{fig:prettyenv} for @{ML_type "Type.tyenv"}s. For the type
-  environment in the example this function prints out the more legible:
-
-
-  @{ML_response_fake [display, gray]
-  "pretty_tyenv @{context} tyenv_unif"
-  "[?'a := ?'b list, ?'b := nat]"}
-
-  The way the unification function @{ML typ_unify in Sign} is implemented 
-  using an initial type environment and initial index makes it easy to
-  unify more than two terms. For example 
-*}
-
-ML %linenosgray{*val (tyenvs, _) = let
-  val tys1 = (@{typ_pat "?'a"}, @{typ_pat "?'b list"})
-  val tys2 = (@{typ_pat "?'b"}, @{typ_pat "nat"})
-in
-  fold (Sign.typ_unify @{theory}) [tys1, tys2] (Vartab.empty, 0) 
-end*}
-
-text {*
-  The index @{text 0} in Line 5 is the maximal index of the schematic type
-  variables occurring in @{text tys1} and @{text tys2}. This index will be
-  increased whenever a new schematic type variable is introduced during
-  unification.  This is for example the case when two schematic type variables
-  have different, incomparable sorts. Then a new schematic type variable is
-  introduced with the combined sorts. To show this let us assume two sorts,
-  say @{text "s1"} and @{text "s2"}, which we attach to the schematic type
-  variables @{text "?'a"} and @{text "?'b"}. Since we do not make any
-  assumption about the sorts, they are incomparable.
-*}
-
-ML{*val (tyenv, index) = let
-  val ty1 = @{typ_pat "?'a::s1"}
-  val ty2 = @{typ_pat "?'b::s2"}
-in
-  Sign.typ_unify @{theory} (ty1, ty2) (Vartab.empty, 0) 
-end*}
-
-text {*
-  To print out the result type environment we switch on the printing 
-  of sort information by setting @{ML_ind show_sorts in Syntax} to 
-  true. This allows us to inspect the typing environment.
-
-  @{ML_response_fake [display,gray]
-  "pretty_tyenv @{context} tyenv"
-  "[?'a::s1 := ?'a1::{s1, s2}, ?'b::s2 := ?'a1::{s1, s2}]"}
-
-  As can be seen, the type variables @{text "?'a"} and @{text "?'b"} are instantiated
-  with a new type variable @{text "?'a1"} with sort @{text "{s1, s2}"}. Since a new
-  type variable has been introduced the @{ML index}, originally being @{text 0}, 
-  has been increased to @{text 1}.
-
-  @{ML_response [display,gray]
-  "index"
-  "1"}
-
-  Let us now return to the unification problem @{text "?'a * ?'b"} and 
-  @{text "?'b list * nat"} from the beginning of this section, and the 
-  calculated type environment @{ML tyenv_unif}:
-
-  @{ML_response_fake [display, gray]
-  "pretty_tyenv @{context} tyenv_unif"
-  "[?'a := ?'b list, ?'b := nat]"}
-
-  Observe that the type environment which the function @{ML typ_unify in
-  Sign} returns is in \emph{not} an instantiation in fully solved form: while @{text
-  "?'b"} is instantiated to @{typ nat}, this is not propagated to the
-  instantiation for @{text "?'a"}.  In unification theory, this is often
-  called an instantiation in \emph{triangular form}. These triangular 
-  instantiations, or triangular type environments, are used because of 
-  performance reasons. To apply such a type environment to a type, say @{text "?'a *
-  ?'b"}, you should use the function @{ML_ind norm_type in Envir}:
-
-  @{ML_response_fake [display, gray]
-  "Envir.norm_type tyenv_unif @{typ_pat \"?'a * ?'b\"}"
-  "nat list * nat"}
-
-  Matching of types can be done with the function @{ML_ind typ_match in Sign}
-  also from the structure @{ML_struct Sign}. This function returns a @{ML_type
-  Type.tyenv} as well, but might raise the exception @{text TYPE_MATCH} in case
-  of failure. For example
-*}
-
-ML{*val tyenv_match = let
-  val pat = @{typ_pat "?'a * ?'b"}
-  and ty  = @{typ_pat "bool list * nat"}
-in
-  Sign.typ_match @{theory} (pat, ty) Vartab.empty 
-end*}
-
-text {*
-  Printing out the calculated matcher gives
-
-  @{ML_response_fake [display,gray]
-  "pretty_tyenv @{context} tyenv_match"
-  "[?'a := bool list, ?'b := nat]"}
-  
-  Unlike unification, which uses the function @{ML norm_type in Envir}, 
-  applying the matcher to a type needs to be done with the function
-  @{ML_ind subst_type in Envir}. For example
-
-  @{ML_response_fake [display, gray]
-  "Envir.subst_type tyenv_match @{typ_pat \"?'a * ?'b\"}"
-  "bool list * nat"}
-
-  Be careful to observe the difference: use always 
-  @{ML subst_type in Envir} for matchers and @{ML norm_type in Envir} 
-  for unifiers. To show the difference, let us calculate the 
-  following matcher:
-*}
-
-ML{*val tyenv_match' = let
-  val pat = @{typ_pat "?'a * ?'b"}
-  and ty  = @{typ_pat "?'b list * nat"}
-in
-  Sign.typ_match @{theory} (pat, ty) Vartab.empty 
-end*}
-
-text {*
-  Now @{ML tyenv_unif} is equal to @{ML tyenv_match'}. If we apply 
-  @{ML norm_type in Envir} to the type @{text "?'a * ?'b"} we obtain
-
-  @{ML_response_fake [display, gray]
-  "Envir.norm_type tyenv_match' @{typ_pat \"?'a * ?'b\"}"
-  "nat list * nat"}
-
-  which does not solve the matching problem, and if
-  we apply @{ML subst_type in Envir} to the same type we obtain
-
-  @{ML_response_fake [display, gray]
-  "Envir.subst_type tyenv_unif @{typ_pat \"?'a * ?'b\"}"
-  "?'b list * nat"}
-  
-  which does not solve the unification problem.
-
-  \begin{readmore}
-  Unification and matching for types is implemented
-  in @{ML_file "Pure/type.ML"}. The ``interface'' functions for them
-  are in @{ML_file "Pure/sign.ML"}. Matching and unification produce type environments
-  as results. These are implemented in @{ML_file "Pure/envir.ML"}.
-  This file also includes the substitution and normalisation functions,
-  which apply a type environment to a type. Type environments are lookup 
-  tables which are implemented in @{ML_file "Pure/term_ord.ML"}.
-  \end{readmore}
-*}
-
-text {*
-  Unification and matching of terms is substantially more complicated than the
-  type-case. The reason is that terms have abstractions and, in this context,  
-  unification or matching modulo plain equality is often not meaningful. 
-  Nevertheless, Isabelle implements the function @{ML_ind
-  first_order_match in Pattern} for terms.  This matching function returns a
-  type environment and a term environment.  To pretty print the latter we use
-  the function @{text "pretty_env"}:
-*}
-
-ML{*fun pretty_env ctxt env =
-let
-  fun get_trms (v, (T, t)) = (Var (v, T), t) 
-  val print = pairself (string_of_term ctxt)
-in
-  pretty_helper (print o get_trms) env 
-end*}
-
-text {*
-  As can be seen from the @{text "get_trms"}-function, a term environment associates 
-  a schematic term variable with a type and a term.  An example of a first-order 
-  matching problem is the term @{term "P (\<lambda>a b. Q b a)"} and the pattern 
-  @{text "?X ?Y"}.
-*}
-
-ML{*val (_, fo_env) = let
-  val fo_pat = @{term_pat "(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y"}
-  val trm_a = @{term "P::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool"} 
-  val trm_b = @{term "\<lambda>a b. (Q::nat\<Rightarrow>nat\<Rightarrow>nat) b a"}
-  val init = (Vartab.empty, Vartab.empty) 
-in
-  Pattern.first_order_match @{theory} (fo_pat, trm_a $ trm_b) init
-end *}
-
-text {*
-  In this example we annotated explicitly types because then 
-  the type environment is empty and can be ignored. The 
-  resulting term environment is
-
-  @{ML_response_fake [display, gray]
-  "pretty_env @{context} fo_env"
-  "[?X := P, ?Y := \<lambda>a b. Q b a]"}
-
-  The matcher can be applied to a term using the function @{ML_ind subst_term
-  in Envir} (remember the same convention for types applies to terms: @{ML
-  subst_term in Envir} is for matchers and @{ML norm_term in Envir} for
-  unifiers). The function @{ML subst_term in Envir} expects a type environment,
-  which is set to empty in the example below, and a term environment.
-
-  @{ML_response_fake [display, gray]
-  "let
-  val trm = @{term_pat \"(?X::(nat\<Rightarrow>nat\<Rightarrow>nat)\<Rightarrow>bool) ?Y\"}
-in
-  Envir.subst_term (Vartab.empty, fo_env) trm
-  |> string_of_term @{context}
-  |> tracing
-end"
-  "P (\<lambda>a b. Q b a)"}
-
-  First-order matching is useful for matching against applications and
-  variables. It can deal also with abstractions and a limited form of
-  alpha-equivalence, but this kind of matching should be used with care, since
-  it is not clear whether the result is meaningful. A meaningful example is
-  matching @{text "\<lambda>x. P x"} against the pattern @{text "\<lambda>y. ?X y"}. In this
-  case, first-order matching produces @{text "[?X := P]"}.
-
-  @{ML_response_fake [display, gray]
-  "let
-  val fo_pat = @{term_pat \"\<lambda>y. (?X::nat\<Rightarrow>bool) y\"}
-  val trm = @{term \"\<lambda>x. (P::nat\<Rightarrow>bool) x\"} 
-  val init = (Vartab.empty, Vartab.empty) 
-in
-  Pattern.first_order_match @{theory} (fo_pat, trm) init
-  |> snd 
-  |> pretty_env @{context} 
-end"
-  "[?X := P]"}
-*}
-
-text {*
-  Unification of abstractions is more thoroughly studied in the context
-  of higher-order pattern unification and higher-order pattern matching.  A
-  \emph{\index*{pattern}} is an abstraction term whose ``head symbol'' (that is the
-  first symbol under an abstraction) is either a constant, a schematic or a free
-  variable. If it is a schematic variable then it can be only applied with
-  distinct bound variables. This excludes terms where a schematic variable is an
-  argument of another one and where a schematic variable is applied
-  twice with the same bound variable. The function @{ML_ind pattern in Pattern}
-  in the structure @{ML_struct Pattern} tests whether a term satisfies these
-  restrictions.
-
-  @{ML_response [display, gray]
-  "let
-  val trm_list = 
-        [@{term_pat \"?X\"},              @{term_pat \"a\"},
-         @{term_pat \"\<lambda>a b. ?X a b\"},    @{term_pat \"\<lambda>a b. (op +) a b\"},
-         @{term_pat \"\<lambda>a. (op +) a ?Y\"}, @{term_pat \"?X ?Y\"},
-         @{term_pat \"\<lambda>a b. ?X a b ?Y\"}, @{term_pat \"\<lambda>a. ?X a a\"}] 
-in
-  map Pattern.pattern trm_list
-end"
-  "[true, true, true, true, true, false, false, false]"}
-
-  The point of the restriction to patterns is that unification and matching 
-  are decidable and produce most general unifiers, respectively matchers. 
-  In this way, matching and unification can be implemented as functions that 
-  produce a type and term environment (unification actually returns a 
-  record of type @{ML_type Envir.env} containing a maxind, a type environment 
-  and a term environment). The corresponding functions are @{ML_ind match in Pattern},
-  and @{ML_ind unify in Pattern} both implemented in the structure
-  @{ML_struct Pattern}. An example for higher-order pattern unification is
-
-  @{ML_response_fake [display, gray]
-  "let
-  val trm1 = @{term_pat \"\<lambda>x y. g (?X y x) (f (?Y x))\"}
-  val trm2 = @{term_pat \"\<lambda>u v. g u (f u)\"}
-  val init = Envir.empty 0
-  val env = Pattern.unify @{theory} (trm1, trm2) init
-in
-  pretty_env @{context} (Envir.term_env env)
-end"
-  "[?X := \<lambda>y x. x, ?Y := \<lambda>x. x]"}
-
-  The function @{ML_ind "Envir.empty"} generates a record with a specified
-  max-index for the schematic variables (in the example the index is @{text
-  0}) and empty type and term environments. The function @{ML_ind
-  "Envir.term_env"} pulls out the term environment from the result record. The
-  function for type environment is @{ML_ind "Envir.type_env"}. An assumption of
-  this function is that the terms to be unified have already the same type. In
-  case of failure, the exceptions that are raised are either @{text Pattern},
-  @{text MATCH} or @{text Unif}.
-
-  As mentioned before, unrestricted higher-order unification, respectively
-  higher-order matching, is in general undecidable and might also not posses a
-  single most general solution. Therefore Isabelle implements the unification
-  function @{ML_ind unifiers in Unify} so that it returns a lazy list of
-  potentially infinite unifiers.  An example is as follows
-*}
-
-ML{*val uni_seq =
-let 
-  val trm1 = @{term_pat "?X ?Y"}
-  val trm2 = @{term "f a"}
-  val init = Envir.empty 0
-in
-  Unify.unifiers (@{theory}, init, [(trm1, trm2)])
-end *}
-
-text {*
-  The unifiers can be extracted from the lazy sequence using the 
-  function @{ML_ind "Seq.pull"}. In the example we obtain three 
-  unifiers @{text "un1\<dots>un3"}.
-*}
-
-ML{*val SOME ((un1, _), next1) = Seq.pull uni_seq;
-val SOME ((un2, _), next2) = Seq.pull next1;
-val SOME ((un3, _), next3) = Seq.pull next2;
-val NONE = Seq.pull next3 *}
-
-text {*
-  \footnote{\bf FIXME: what is the list of term pairs in the unifier: flex-flex pairs?}
-
-  We can print them out as follows.
-
-  @{ML_response_fake [display, gray]
-  "pretty_env @{context} (Envir.term_env un1);
-pretty_env @{context} (Envir.term_env un2);
-pretty_env @{context} (Envir.term_env un3)"
-  "[?X := \<lambda>a. a, ?Y := f a]
-[?X := f, ?Y := a]
-[?X := \<lambda>b. f a]"}
-
-
-  In case of failure the function @{ML_ind unifiers in Unify} does not raise
-  an exception, rather returns the empty sequence. For example
-
-  @{ML_response [display, gray]
-"let 
-  val trm1 = @{term \"a\"}
-  val trm2 = @{term \"b\"}
-  val init = Envir.empty 0
-in
-  Unify.unifiers (@{theory}, init, [(trm1, trm2)])
-  |> Seq.pull
-end"
-"NONE"}
-
-  In order to find a
-  reasonable solution for a unification problem, Isabelle also tries first to
-  solve the problem by higher-order pattern unification. 
-
-  For higher-order
-  matching the function is called @{ML_ind matchers in Unify} implemented
-  in the structure @{ML_struct Unify}. Also this
-  function returns sequences with possibly more than one matcher.
-  Like @{ML unifiers in Unify}, this function does not raise an exception
-  in case of failure, but returns an empty sequence. It also first tries 
-  out whether the matching problem can be solved by first-order matching.
-
-  \begin{readmore}
-  Unification and matching of higher-order patterns is implemented in 
-  @{ML_file "Pure/pattern.ML"}. This file also contains a first-order matcher
-  for terms. Full higher-order unification is implemented
-  in @{ML_file "Pure/unify.ML"}. It uses lazy sequences which are implemented
-  in @{ML_file "Pure/General/seq.ML"}.
-  \end{readmore}
-*}
-
-
-
-
-section {* Type-Checking\label{sec:typechecking} *}
-
-text {* 
-  Remember Isabelle follows the Church-style typing for terms, i.e., a term contains 
-  enough typing information (constants, free variables and abstractions all have typing 
-  information) so that it is always clear what the type of a term is. 
-  Given a well-typed term, the function @{ML_ind type_of in Term} returns the 
-  type of a term. Consider for example:
-
-  @{ML_response [display,gray] 
-  "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"}
-
-  To calculate the type, this function traverses the whole term and will
-  detect any typing inconsistency. For example changing the type of the variable 
-  @{term "x"} from @{typ "nat"} to @{typ "int"} will result in the error message: 
-
-  @{ML_response_fake [display,gray] 
-  "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" 
-  "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"}
-
-  Since the complete traversal might sometimes be too costly and
-  not necessary, there is the function @{ML_ind fastype_of in Term}, which 
-  also returns the type of a term.
-
-  @{ML_response [display,gray] 
-  "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"}
-
-  However, efficiency is gained on the expense of skipping some tests. You 
-  can see this in the following example
-
-   @{ML_response [display,gray] 
-  "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" "bool"}
-
-  where no error is detected.
-
-  Sometimes it is a bit inconvenient to construct a term with 
-  complete typing annotations, especially in cases where the typing 
-  information is redundant. A short-cut is to use the ``place-holder'' 
-  type @{ML_ind dummyT in Term} and then let type-inference figure out the 
-  complete type. An example is as follows:
-
-  @{ML_response_fake [display,gray] 
-"let
-  val c = Const (@{const_name \"plus\"}, dummyT) 
-  val o = @{term \"1::nat\"} 
-  val v = Free (\"x\", dummyT)
-in   
-  Syntax.check_term @{context} (c $ o $ v)
-end"
-"Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $
-  Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"}
-
-  Instead of giving explicitly the type for the constant @{text "plus"} and the free 
-  variable @{text "x"}, type-inference fills in the missing information.
-
-  \begin{readmore}
-  See @{ML_file "Pure/Syntax/syntax.ML"} where more functions about reading,
-  checking and pretty-printing of terms are defined. Functions related to
-  type-inference are implemented in @{ML_file "Pure/type.ML"} and 
-  @{ML_file "Pure/type_infer.ML"}. 
-  \end{readmore}
-
-  \footnote{\bf FIXME: say something about sorts.}
-  \footnote{\bf FIXME: give a ``readmore''.}
-
-  \begin{exercise}
-  Check that the function defined in Exercise~\ref{fun:revsum} returns a
-  result that type-checks. See what happens to the  solutions of this 
-  exercise given in Appendix \ref{ch:solutions} when they receive an 
-  ill-typed term as input.
-  \end{exercise}
-*}
-
-section {* Certified Terms and Certified Types *}
-
-text {*
-  You can freely construct and manipulate @{ML_type "term"}s and @{ML_type
-  typ}es, since they are just arbitrary unchecked trees. However, you
-  eventually want to see if a term is well-formed, or type-checks, relative to
-  a theory.  Type-checking is done via the function @{ML_ind cterm_of in Thm}, which
-  converts a @{ML_type term} into a @{ML_type cterm}, a \emph{certified}
-  term. Unlike @{ML_type term}s, which are just trees, @{ML_type "cterm"}s are
-  abstract objects that are guaranteed to be type-correct, and they can only
-  be constructed via ``official interfaces''.
-
-  Certification is always relative to a theory context. For example you can 
-  write:
-
-  @{ML_response_fake [display,gray] 
-  "cterm_of @{theory} @{term \"(a::nat) + b = c\"}" 
-  "a + b = c"}
-
-  This can also be written with an antiquotation:
-
-  @{ML_response_fake [display,gray] 
-  "@{cterm \"(a::nat) + b = c\"}" 
-  "a + b = c"}
-
-  Attempting to obtain the certified term for
-
-  @{ML_response_fake_both [display,gray] 
-  "@{cterm \"1 + True\"}" 
-  "Type unification failed \<dots>"}
-
-  yields an error (since the term is not typable). A slightly more elaborate
-  example that type-checks is:
-
-@{ML_response_fake [display,gray] 
-"let
-  val natT = @{typ \"nat\"}
-  val zero = @{term \"0::nat\"}
-  val plus = Const (@{const_name plus}, [natT, natT] ---> natT)
-in
-  cterm_of @{theory} (plus $ zero $ zero)
-end" 
-  "0 + 0"}
-
-  In Isabelle not just terms need to be certified, but also types. For example, 
-  you obtain the certified type for the Isabelle type @{typ "nat \<Rightarrow> bool"} on 
-  the ML-level as follows:
-
-  @{ML_response_fake [display,gray]
-  "ctyp_of @{theory} (@{typ nat} --> @{typ bool})"
-  "nat \<Rightarrow> bool"}
-
-  or with the antiquotation:
-
-  @{ML_response_fake [display,gray]
-  "@{ctyp \"nat \<Rightarrow> bool\"}"
-  "nat \<Rightarrow> bool"}
-
-  Since certified terms are, unlike terms, abstract objects, we cannot
-  pattern-match against them. However, we can construct them. For example
-  the function @{ML_ind capply in Thm} produces a certified application.
-
-  @{ML_response_fake [display,gray]
-  "Thm.capply @{cterm \"P::nat \<Rightarrow> bool\"} @{cterm \"3::nat\"}"
-  "P 3"}
-
-  Similarly the function @{ML_ind list_comb in Drule} from the structure @{ML_struct Drule}
-  applies a list of @{ML_type cterm}s.
-
-  @{ML_response_fake [display,gray]
-  "let
-  val chead = @{cterm \"P::unit \<Rightarrow> nat \<Rightarrow> bool\"}
-  val cargs = [@{cterm \"()\"}, @{cterm \"3::nat\"}]
-in
-  Drule.list_comb (chead, cargs)
-end"
-  "P () 3"}
-
-  \begin{readmore}
-  For functions related to @{ML_type cterm}s and @{ML_type ctyp}s see 
-  the files @{ML_file "Pure/thm.ML"}, @{ML_file "Pure/more_thm.ML"} and
-  @{ML_file "Pure/drule.ML"}.
-  \end{readmore}
-*}
-
-section {* Theorems *}
-
-text {*
-  Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} 
-  that can only be built by going through interfaces. As a consequence, every proof 
-  in Isabelle is correct by construction. This follows the tradition of the LCF-approach.
-
-
-  To see theorems in ``action'', let us give a proof on the ML-level for the following 
-  statement:
-*}
-
-  lemma 
-    assumes assm\<^isub>1: "\<And>(x::nat). P x \<Longrightarrow> Q x" 
-    and     assm\<^isub>2: "P t"
-    shows "Q t"(*<*)oops(*>*) 
-
-text {*
-  The corresponding ML-code is as follows:
-*}
-
-ML{*val my_thm = 
-let
-  val assm1 = @{cprop "\<And>(x::nat). P x \<Longrightarrow> Q x"}
-  val assm2 = @{cprop "(P::nat \<Rightarrow> bool) t"}
-
-  val Pt_implies_Qt = 
-        assume assm1
-        |> forall_elim @{cterm "t::nat"}
-  
-  val Qt = implies_elim Pt_implies_Qt (assume assm2)
-in
-  Qt 
-  |> implies_intr assm2
-  |> implies_intr assm1
-end*}
-
-text {* 
-  If we print out the value of @{ML my_thm} then we see only the 
-  final statement of the theorem.
-
-  @{ML_response_fake [display, gray]
-  "tracing (string_of_thm @{context} my_thm)"
-  "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}
-
-  However, internally the code-snippet constructs the following 
-  proof.
-
-  \[
-  \infer[(@{text "\<Longrightarrow>"}$-$intro)]{\vdash @{prop "(\<And>x. P x \<Longrightarrow> Q x) \<Longrightarrow> P t \<Longrightarrow> Q t"}}
-    {\infer[(@{text "\<Longrightarrow>"}$-$intro)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "P t \<Longrightarrow> Q t"}}
-       {\infer[(@{text "\<Longrightarrow>"}$-$elim)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"}, @{prop "P t"} \vdash @{prop "Q t"}}
-          {\infer[(@{text "\<And>"}$-$elim)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "P t \<Longrightarrow> Q t"}}
-                 {\infer[(assume)]{@{prop "\<And>x. P x \<Longrightarrow> Q x"} \vdash @{prop "\<And>x. P x \<Longrightarrow> Q x"}}{}}
-                 &
-           \infer[(assume)]{@{prop "P t"} \vdash @{prop "P t"}}{}
-          }
-       }
-    }
-  \]
-
-  While we obtained a theorem as result, this theorem is not
-  yet stored in Isabelle's theorem database. Consequently, it cannot be 
-  referenced on the user level. One way to store it in the theorem database is
-  by using the function @{ML_ind note in Local_Theory}.\footnote{\bf FIXME: make sure a pointer
-  to the section about local-setup is given earlier.}
-*}
-
-local_setup %gray {*
-  Local_Theory.note ((@{binding "my_thm"}, []), [my_thm]) #> snd *}
-
-text {*
-  The fourth argument of @{ML note in Local_Theory} is the list of theorems we
-  want to store under a name. We can store more than one under a single name. 
-  The first argument @{ML_ind theoremK in Thm} is
-  a kind indicator, which classifies the theorem. There are several such kind
-  indicators: for a theorem arising from a definition you should use @{ML_ind
-  definitionK in Thm}, and for
-  ``normal'' theorems the kinds @{ML_ind theoremK in Thm} or @{ML_ind lemmaK
-  in Thm}.  The second argument of @{ML note in Local_Theory} is the name under
-  which we store the theorem or theorems. The third argument can contain a
-  list of theorem attributes, which we will explain in detail in
-  Section~\ref{sec:attributes}. Below we just use one such attribute for
-  adding the theorem to the simpset:
-*}
-
-local_setup %gray {*
-  Local_Theory.note ((@{binding "my_thm_simp"}, 
-       [Attrib.internal (K Simplifier.simp_add)]), [my_thm]) #> snd *}
-
-text {*
-  Note that we have to use another name under which the theorem is stored,
-  since Isabelle does not allow us to call  @{ML_ind note in Local_Theory} twice
-  with the same name. The attribute needs to be wrapped inside the function @{ML_ind
-  internal in Attrib} from the structure @{ML_struct Attrib}. If we use the function 
-  @{ML get_thm_names_from_ss} from
-  the previous chapter, we can check whether the theorem has actually been
-  added.
-
-
-  @{ML_response [display,gray]
-  "let
-  fun pred s = match_string \"my_thm_simp\" s
-in
-  exists pred (get_thm_names_from_ss @{simpset})
-end"
-  "true"}
-
-  The main point of storing the theorems @{thm [source] my_thm} and @{thm
-  [source] my_thm_simp} is that they can now also be referenced with the
-  \isacommand{thm}-command on the user-level of Isabelle
-
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "my_thm"}\isanewline
-   @{text ">"}~@{prop "\<lbrakk>\<And>x. P x \<Longrightarrow> Q x; P t\<rbrakk> \<Longrightarrow> Q t"}
-  \end{isabelle}
-
-  or with the @{text "@{thm \<dots>}"}-antiquotation on the ML-level. Otherwise the 
-  user has no access to these theorems. 
-
-  Recall that Isabelle does not let you call @{ML note in Local_Theory} twice
-  with the same theorem name. In effect, once a theorem is stored under a name, 
-  this association is fixed. While this is a ``safety-net'' to make sure a
-  theorem name refers to a particular theorem or collection of theorems, it is 
-  also a bit too restrictive in cases where a theorem name should refer to a 
-  dynamically expanding list of theorems (like a simpset). Therefore Isabelle 
-  also implements a mechanism where a theorem name can refer to a custom theorem 
-  list. For this you can use the function @{ML_ind add_thms_dynamic in PureThy}. 
-  To see how it works let us assume we defined our own theorem list @{text MyThmList}.
-*}
-
-ML{*structure MyThmList = Generic_Data
-  (type T = thm list
-   val empty = []
-   val extend = I
-   val merge = merge Thm.eq_thm_prop)
-
-fun update thm = Context.theory_map (MyThmList.map (Thm.add_thm thm))*}
-
-text {*
-  The function @{ML update} allows us to update the theorem list, for example
-  by adding the theorem @{thm [source] TrueI}.
-*}
-
-setup %gray {* update @{thm TrueI} *}
- 
-text {*
-  We can now install the theorem list so that it is visible to the user and 
-  can be refered to by a theorem name. For this need to call 
-  @{ML_ind add_thms_dynamic in PureThy}
-*}
-
-setup %gray {* 
-  PureThy.add_thms_dynamic (@{binding "mythmlist"}, MyThmList.get) 
-*}
-
-text {*
-  with a name and a function that accesses the theorem list. Now if the
-  user issues the command
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "mythmlist"}\\
-  @{text "> True"}
-  \end{isabelle}
-
-  the current content of the theorem list is displayed. If more theorems are stored in 
-  the list, say
-*}
-
-setup %gray {* update @{thm FalseE} *}
-
-text {*
-  then the same command produces
-  
-  \begin{isabelle}
-  \isacommand{thm}~@{text "mythmlist"}\\
-  @{text "> False \<Longrightarrow> ?P"}\\
-  @{text "> True"}
-  \end{isabelle}
-
-  There is a multitude of functions in the structures @{ML_struct Thm} and @{ML_struct Drule} 
-  for managing or manipulating theorems. For example 
-  we can test theorems for alpha equality. Suppose you proved the following three 
-  theorems.
-*}
-
-lemma
-  shows thm1: "\<forall>x. P x" 
-  and   thm2: "\<forall>y. P y" 
-  and   thm3: "\<forall>y. Q y" sorry
-
-text {*
-  Testing them for alpha equality using the function @{ML_ind eq_thm in Thm} produces:
-
-  @{ML_response [display,gray]
-"(Thm.eq_thm (@{thm thm1}, @{thm thm2}),
- Thm.eq_thm (@{thm thm2}, @{thm thm3}))"
-"(true, false)"}
-
-  Many functions destruct theorems into @{ML_type cterm}s. For example
-  the functions @{ML_ind lhs_of in Thm} and @{ML_ind rhs_of in Thm} return 
-  the left and right-hand side, respectively, of a meta-equality.
-
-  @{ML_response_fake [display,gray]
-  "let
-  val eq = @{thm True_def}
-in
-  (Thm.lhs_of eq, Thm.rhs_of eq) 
-  |> pairself (string_of_cterm @{context})
-end"
-  "(True, (\<lambda>x. x) = (\<lambda>x. x))"}
-
-  Other function produce terms that can be pattern-matched. 
-  Suppose the following two theorems.
-*}
-
-lemma  
-  shows foo_test1: "A \<Longrightarrow> B \<Longrightarrow> C" 
-  and   foo_test2: "A \<longrightarrow> B \<longrightarrow> C" sorry
-
-text {*
-  We can destruct them into premises and conclusions as follows. 
-
- @{ML_response_fake [display,gray]
-"let
-  val ctxt = @{context}
-  fun prems_and_concl thm =
-     [\"Premises: \"   ^ (string_of_terms ctxt (Thm.prems_of thm))] @ 
-     [\"Conclusion: \" ^ (string_of_term ctxt (Thm.concl_of thm))]
-     |> cat_lines
-     |> tracing
-in
-  prems_and_concl @{thm foo_test1};
-  prems_and_concl @{thm foo_test2}
-end"
-"Premises: ?A, ?B
-Conclusion: ?C
-Premises: 
-Conclusion: ?A \<longrightarrow> ?B \<longrightarrow> ?C"}
-
-  Note that in the second case, there is no premise.
-
-  \begin{readmore}
-  The basic functions for theorems are defined in
-  @{ML_file "Pure/thm.ML"}, @{ML_file "Pure/more_thm.ML"} and @{ML_file "Pure/drule.ML"}. 
-  \end{readmore}
-
-  Although we will explain the simplifier in more detail as tactic in 
-  Section~\ref{sec:simplifier}, the simplifier 
-  can be used to work directly over theorems, for example to unfold definitions. To show
-  this, we build the theorem @{term "True \<equiv> True"} (Line 1) and then 
-  unfold the constant @{term "True"} according to its definition (Line 2).
-
-  @{ML_response_fake [display,gray,linenos]
-  "Thm.reflexive @{cterm \"True\"}
-  |> Simplifier.rewrite_rule [@{thm True_def}]
-  |> string_of_thm @{context}
-  |> tracing"
-  "(\<lambda>x. x) = (\<lambda>x. x) \<equiv> (\<lambda>x. x) = (\<lambda>x. x)"}
-
-  Often it is necessary to transform theorems to and from the object 
-  logic, that is replacing all @{text "\<longrightarrow>"} and @{text "\<forall>"} by @{text "\<Longrightarrow>"} 
-  and @{text "\<And>"}, or the other way around.  A reason for such a transformation 
-  might be stating a definition. The reason is that definitions can only be 
-  stated using object logic connectives, while theorems using the connectives 
-  from the meta logic are more convenient for reasoning. Therefore there are
-  some build in functions which help with these transformations. The function 
-  @{ML_ind rulify in ObjectLogic} 
-  replaces all object connectives by equivalents in the meta logic. For example
-
-  @{ML_response_fake [display, gray]
-  "ObjectLogic.rulify @{thm foo_test2}"
-  "\<lbrakk>?A; ?B\<rbrakk> \<Longrightarrow> ?C"}
-
-  The transformation in the other direction can be achieved with function
-  @{ML_ind atomize in ObjectLogic} and the following code.
-
-  @{ML_response_fake [display,gray]
-  "let
-  val thm = @{thm foo_test1}
-  val meta_eq = ObjectLogic.atomize (cprop_of thm)
-in
-  MetaSimplifier.rewrite_rule [meta_eq] thm
-end"
-  "?A \<longrightarrow> ?B \<longrightarrow> ?C"}
-
-  In this code the function @{ML atomize in ObjectLogic} produces 
-  a meta-equation between the given theorem and the theorem transformed
-  into the object logic. The result is the theorem with object logic 
-  connectives. However, in order to completely transform a theorem
-  involving meta variables, such as @{thm [source] list.induct}, which 
-  is of the form 
-
-  @{thm [display] list.induct}
-
-  we have to first abstract over the meta variables @{text "?P"} and 
-  @{text "?list"}. For this we can use the function 
-  @{ML_ind forall_intr_vars in Drule}. This allows us to implement the
-  following function for atomizing a theorem.
-*}
-
-ML{*fun atomize_thm thm =
-let
-  val thm' = forall_intr_vars thm
-  val thm'' = ObjectLogic.atomize (cprop_of thm')
-in
-  MetaSimplifier.rewrite_rule [thm''] thm'
-end*}
-
-text {*
-  This function produces for the theorem @{thm [source] list.induct}
-
-  @{ML_response_fake [display, gray]
-  "atomize_thm @{thm list.induct}"
-  "\<forall>P list. P [] \<longrightarrow> (\<forall>a list. P list \<longrightarrow> P (a # list)) \<longrightarrow> P list"}
-
-  \footnote{\bf FIXME: say someting about @{ML_ind standard in Drule}.}
-
-  Theorems can also be produced from terms by giving an explicit proof. 
-  One way to achieve this is by using the function @{ML_ind prove in Goal}
-  in the structure @{ML_struct Goal}. For example below we use this function
-  to prove the term @{term "P \<Longrightarrow> P"}.
-  
-  @{ML_response_fake [display,gray]
-  "let
-  val trm = @{term \"P \<Longrightarrow> P::bool\"}
-  val tac = K (atac 1)
-in
-  Goal.prove @{context} [\"P\"] [] trm tac
-end"
-  "?P \<Longrightarrow> ?P"}
-
-  This function takes first a context and second a list of strings. This list
-  specifies which variables should be turned into schematic variables once the term
-  is proved.  The fourth argument is the term to be proved. The fifth is a
-  corresponding proof given in form of a tactic (we explain tactics in
-  Chapter~\ref{chp:tactical}). In the code above, the tactic proves the theorem
-  by assumption. As before this code will produce a theorem, but the theorem
-  is not yet stored in the theorem database. 
-
-  While the LCF-approach of going through interfaces ensures soundness in Isabelle, there
-  is the function @{ML_ind make_thm in Skip_Proof} in the structure 
-  @{ML_struct Skip_Proof} that allows us to turn any proposition into a theorem.
-  Potentially making the system unsound.  This is sometimes useful for developing 
-  purposes, or when explicit proof construction should be omitted due to performace 
-  reasons. An example of this function is as follows:
-
-  @{ML_response_fake [display, gray]
-  "Skip_Proof.make_thm @{theory} @{prop \"True = False\"}"
-  "True = False"}
-
-  The function @{ML make_thm in Skip_Proof} however only works if 
-  the ``quick-and-dirty'' mode is switched on. 
-
-  Theorems also contain auxiliary data, such as the name of the theorem, its
-  kind, the names for cases and so on. This data is stored in a string-string
-  list and can be retrieved with the function @{ML_ind get_tags in
-  Thm}. Assume you prove the following lemma.
-*}
-
-lemma foo_data: 
-  shows "P \<Longrightarrow> P \<Longrightarrow> P" by assumption
-
-text {*
-  The auxiliary data of this lemma can be retrieved using the function 
-  @{ML_ind get_tags in Thm}. So far the the auxiliary data of this lemma is 
-
-  @{ML_response_fake [display,gray]
-  "Thm.get_tags @{thm foo_data}"
-  "[(\"name\", \"General.foo_data\"), (\"kind\", \"lemma\")]"}
-
-  consisting of a name and a kind.  When we store lemmas in the theorem database, 
-  we might want to explicitly extend this data by attaching case names to the 
-  two premises of the lemma.  This can be done with the function @{ML_ind name in Rule_Cases}
-  from the structure @{ML_struct Rule_Cases}.
-*}
-
-local_setup %gray {*
-  Local_Theory.note ((@{binding "foo_data'"}, []), 
-    [(Rule_Cases.name ["foo_case_one", "foo_case_two"] 
-       @{thm foo_data})]) #> snd *}
-
-text {*
-  The data of the theorem @{thm [source] foo_data'} is then as follows:
-
-  @{ML_response_fake [display,gray]
-  "Thm.get_tags @{thm foo_data'}"
-  "[(\"name\", \"General.foo_data'\"), (\"kind\", \"lemma\"), 
- (\"case_names\", \"foo_case_one;foo_case_two\")]"}
-
-  You can observe the case names of this lemma on the user level when using 
-  the proof methods @{text cases} and @{text induct}. In the proof below
-*}
-
-lemma
-  shows "Q \<Longrightarrow> Q \<Longrightarrow> Q"
-proof (cases rule: foo_data')
-
-(*<*)oops(*>*)
-text_raw{*
-\begin{tabular}{@ {}l}
-\isacommand{print\_cases}\\
-@{text "> cases:"}\\
-@{text ">   foo_case_one:"}\\
-@{text ">     let \"?case\" = \"?P\""}\\
-@{text ">   foo_case_two:"}\\
-@{text ">     let \"?case\" = \"?P\""}
-\end{tabular}*}
-
-text {*
-  we can proceed by analysing the cases @{text "foo_case_one"} and 
-  @{text "foo_case_two"}. While if the theorem has no names, then
-  the cases have standard names @{text 1}, @{text 2} and so 
-  on. This can be seen in the proof below.
-*}
-
-lemma
-  shows "Q \<Longrightarrow> Q \<Longrightarrow> Q"
-proof (cases rule: foo_data)
-
-(*<*)oops(*>*)
-text_raw{*
-\begin{tabular}{@ {}l}
-\isacommand{print\_cases}\\
-@{text "> cases:"}\\
-@{text ">   1:"}\\
-@{text ">     let \"?case\" = \"?P\""}\\
-@{text ">   2:"}\\
-@{text ">     let \"?case\" = \"?P\""}
-\end{tabular}*}
-
-
-text {*
-  One great feature of Isabelle is its document preparation system, where
-  proved theorems can be quoted in documents referencing directly their
-  formalisation. This helps tremendously to minimise cut-and-paste errors. However,
-  sometimes the verbatim quoting is not what is wanted or what can be shown to
-  readers. For such situations Isabelle allows the installation of \emph{\index*{theorem 
-  styles}}. These are, roughly speaking, functions from terms to terms. The input 
-  term stands for the theorem to be presented; the output can be constructed to
-  ones wishes.  Let us, for example, assume we want to quote theorems without
-  leading @{text \<forall>}-quantifiers. For this we can implement the following function 
-  that strips off @{text "\<forall>"}s.
-*}
-
-ML %linenosgray{*fun strip_allq (Const (@{const_name "All"}, _) $ Abs body) = 
-      Term.dest_abs body |> snd |> strip_allq
-  | strip_allq (Const (@{const_name "Trueprop"}, _) $ t) = 
-      strip_allq t
-  | strip_allq t = t*}
-
-text {*
-  We use in Line 2 the function @{ML_ind dest_abs in Term} for deconstructing abstractions,
-  since this function deals correctly with potential name clashes. This function produces
-  a pair consisting of the variable and the body of the abstraction. We are only interested
-  in the body, which we feed into the recursive call. In Line 3 and 4, we also
-  have to explicitly strip of the outermost @{term Trueprop}-coercion. Now we can 
-  install this function as the theorem style named @{text "my_strip_allq"}. 
-*}
-
-setup %gray {*
-  Term_Style.setup "my_strip_allq" (Scan.succeed (K strip_allq)) 
-*}
-
-text {*
-  We can test this theorem style with the following theorem
-*}
-
-theorem style_test:
-  shows "\<forall>x y z. (x, x) = (y, z)" sorry
-
-text {*
-  Now printing out in a document the theorem @{thm [source] style_test} normally
-  using @{text "@{thm \<dots>}"} produces
-
-  \begin{isabelle}
-  @{text "@{thm style_test}"}\\
-  @{text ">"}~@{thm style_test}
-  \end{isabelle}
-
-  as expected. But with the theorem style @{text "@{thm (my_strip_allq) \<dots>}"} 
-  we obtain
-
-  \begin{isabelle}
-  @{text "@{thm (my_strip_allq) style_test}"}\\
-  @{text ">"}~@{thm (my_strip_allq) style_test}\\
-  \end{isabelle}
-  
-  without the leading quantifiers. We can improve this theorem style by explicitly 
-  giving a list of strings that should be used for the replacement of the
-  variables. For this we implement the function which takes a list of strings
-  and uses them as name in the outermost abstractions.
-*}
-
-ML{*fun rename_allq [] t = t
-  | rename_allq (x::xs) (Const (@{const_name "All"}, U) $ Abs (_, T, t)) = 
-      Const (@{const_name "All"}, U) $ Abs (x, T, rename_allq xs t)
-  | rename_allq xs (Const (@{const_name "Trueprop"}, U) $ t) =
-      rename_allq xs t
-  | rename_allq _ t = t*}
-
-text {*
-  We can now install a the modified theorem style as follows
-*}
-
-setup %gray {* let
-  val parser = Scan.repeat Args.name
-  fun action xs = K (rename_allq xs #> strip_allq)
-in
-  Term_Style.setup "my_strip_allq2" (parser >> action)
-end *}
-
-text {*
-  The parser reads a list of names. In the function @{text action} we first
-  call @{ML rename_allq} with the parsed list, then we call @{ML strip_allq}
-  on the resulting term. We can now suggest, for example, two variables for
-  stripping off the first two @{text \<forall>}-quantifiers.
-
-
-  \begin{isabelle}
-  @{text "@{thm (my_strip_allq2 x' x'') style_test}"}\\
-  @{text ">"}~@{thm (my_strip_allq2 x' x'') style_test}
-  \end{isabelle}
-
-  Such theorem styles allow one to print out theorems in documents formatted to
-  ones heart content. Next we explain theorem attributes, which is another
-  mechanism for dealing with theorems.
-
-  \begin{readmore}
-  Theorem styles are implemented in @{ML_file "Pure/Thy/term_style.ML"}.
-  \end{readmore}
-*}
-
-section {* Theorem Attributes\label{sec:attributes} *}
-
-text {*
-  Theorem attributes are @{text "[symmetric]"}, @{text "[THEN \<dots>]"}, @{text
-  "[simp]"} and so on. Such attributes are \emph{neither} tags \emph{nor} flags
-  annotated to theorems, but functions that do further processing of 
-  theorems. In particular, it is not possible to find out
-  what are all theorems that have a given attribute in common, unless of course
-  the function behind the attribute stores the theorems in a retrievable 
-  data structure. 
-
-  If you want to print out all currently known attributes a theorem can have, 
-  you can use the Isabelle command
-
-  \begin{isabelle}
-  \isacommand{print\_attributes}\\
-  @{text "> COMP:  direct composition with rules (no lifting)"}\\
-  @{text "> HOL.dest:  declaration of Classical destruction rule"}\\
-  @{text "> HOL.elim:  declaration of Classical elimination rule"}\\
-  @{text "> \<dots>"}
-  \end{isabelle}
-  
-  The theorem attributes fall roughly into two categories: the first category manipulates
-  theorems (for example @{text "[symmetric]"} and @{text "[THEN \<dots>]"}), and the second
-  stores theorems somewhere as data (for example @{text "[simp]"}, which adds
-  theorems to the current simpset).
-
-  To explain how to write your own attribute, let us start with an extremely simple 
-  version of the attribute @{text "[symmetric]"}. The purpose of this attribute is
-  to produce the ``symmetric'' version of an equation. The main function behind 
-  this attribute is
-*}
-
-ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*}
-
-text {* 
-  where the function @{ML_ind  rule_attribute in Thm} expects a function taking a 
-  context (which we ignore in the code above) and a theorem (@{text thm}), and 
-  returns another theorem (namely @{text thm} resolved with the theorem 
-  @{thm [source] sym}: @{thm sym[no_vars]}; the function @{ML_ind RS in Drule} 
-  is explained in Section~\ref{sec:simpletacs}). The function 
-  @{ML rule_attribute in Thm} then returns  an attribute.
-
-  Before we can use the attribute, we need to set it up. This can be done
-  using the Isabelle command \isacommand{attribute\_setup} as follows:
-*}
-
-attribute_setup %gray my_sym = 
-  {* Scan.succeed my_symmetric *} "applying the sym rule"
-
-text {*
-  Inside the @{text "\<verbopen> \<dots> \<verbclose>"}, we have to specify a parser
-  for the theorem attribute. Since the attribute does not expect any further 
-  arguments (unlike @{text "[THEN \<dots>]"}, for instance), we use the parser @{ML
-  Scan.succeed}. An example for the attribute @{text "[my_sym]"} is the proof
-*} 
-
-lemma test[my_sym]: "2 = Suc (Suc 0)" by simp
-
-text {*
-  which stores the theorem @{thm test} under the name @{thm [source] test}. You
-  can see this, if you query the lemma: 
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test"}\\
-  @{text "> "}~@{thm test}
-  \end{isabelle}
-
-  We can also use the attribute when referring to this theorem:
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test[my_sym]"}\\
-  @{text "> "}~@{thm test[my_sym]}
-  \end{isabelle}
-
-  An alternative for setting up an attribute is the function @{ML_ind  setup in Attrib}.
-  So instead of using \isacommand{attribute\_setup}, you can also set up the
-  attribute as follows:
-*}
-
-ML{*Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric)
-  "applying the sym rule" *}
-
-text {*
-  This gives a function from @{ML_type "theory -> theory"}, which
-  can be used for example with \isacommand{setup} or with
-  @{ML "Context.>> o Context.map_theory"}.\footnote{\bf FIXME: explain what happens here.}
-
-  As an example of a slightly more complicated theorem attribute, we implement 
-  our own version of @{text "[THEN \<dots>]"}. This attribute will take a list of theorems
-  as argument and resolve the theorem with this list (one theorem 
-  after another). The code for this attribute is
-*}
-
-ML{*fun MY_THEN thms = 
-  Thm.rule_attribute 
-    (fn _ => fn thm => fold (curry ((op RS) o swap)) thms thm)*}
-
-text {* 
-  where @{ML swap} swaps the components of a pair. The setup of this theorem
-  attribute uses the parser @{ML thms in Attrib}, which parses a list of
-  theorems. 
-*}
-
-attribute_setup %gray MY_THEN = {* Attrib.thms >> MY_THEN *} 
-  "resolving the list of theorems with the theorem"
-
-text {* 
-  You can, for example, use this theorem attribute to turn an equation into a 
-  meta-equation:
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test[MY_THEN eq_reflection]"}\\
-  @{text "> "}~@{thm test[MY_THEN eq_reflection]}
-  \end{isabelle}
-
-  If you need the symmetric version as a meta-equation, you can write
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test[MY_THEN sym eq_reflection]"}\\
-  @{text "> "}~@{thm test[MY_THEN sym eq_reflection]}
-  \end{isabelle}
-
-  It is also possible to combine different theorem attributes, as in:
-  
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test[my_sym, MY_THEN eq_reflection]"}\\
-  @{text "> "}~@{thm test[my_sym, MY_THEN eq_reflection]}
-  \end{isabelle}
-  
-  However, here also a weakness of the concept
-  of theorem attributes shows through: since theorem attributes can be
-  arbitrary functions, they do not commute in general. If you try
-
-  \begin{isabelle}
-  \isacommand{thm}~@{text "test[MY_THEN eq_reflection, my_sym]"}\\
-  @{text "> "}~@{text "exception THM 1 raised: RSN: no unifiers"}
-  \end{isabelle}
-
-  you get an exception indicating that the theorem @{thm [source] sym}
-  does not resolve with meta-equations. 
-
-  The purpose of @{ML_ind rule_attribute in Thm} is to directly manipulate
-  theorems.  Another usage of theorem attributes is to add and delete theorems
-  from stored data.  For example the theorem attribute @{text "[simp]"} adds
-  or deletes a theorem from the current simpset. For these applications, you
-  can use @{ML_ind declaration_attribute in Thm}. To illustrate this function,
-  let us introduce a theorem list.
-*}
-
-ML{*structure MyThms = Named_Thms
-  (val name = "attr_thms" 
-   val description = "Theorems for an Attribute") *}
-
-text {* 
-  We are going to modify this list by adding and deleting theorems.
-  For this we use the two functions @{ML MyThms.add_thm} and
-  @{ML MyThms.del_thm}. You can turn them into attributes 
-  with the code
-*}
-
-ML{*val my_add = Thm.declaration_attribute MyThms.add_thm
-val my_del = Thm.declaration_attribute MyThms.del_thm *}
-
-text {* 
-  and set up the attributes as follows
-*}
-
-attribute_setup %gray my_thms = {* Attrib.add_del my_add my_del *} 
-  "maintaining a list of my_thms" 
-
-text {*
-  The parser @{ML_ind  add_del in Attrib} is a predefined parser for 
-  adding and deleting lemmas. Now if you prove the next lemma 
-  and attach to it the attribute @{text "[my_thms]"}
-*}
-
-lemma trueI_2[my_thms]: "True" by simp
-
-text {*
-  then you can see it is added to the initially empty list.
-
-  @{ML_response_fake [display,gray]
-  "MyThms.get @{context}" 
-  "[\"True\"]"}
-
-  You can also add theorems using the command \isacommand{declare}.
-*}
-
-declare test[my_thms] trueI_2[my_thms add]
-
-text {*
-  With this attribute, the @{text "add"} operation is the default and does 
-  not need to be explicitly given. These three declarations will cause the 
-  theorem list to be updated as:
-
-  @{ML_response_fake [display,gray]
-  "MyThms.get @{context}"
-  "[\"True\", \"Suc (Suc 0) = 2\"]"}
-
-  The theorem @{thm [source] trueI_2} only appears once, since the 
-  function @{ML_ind  add_thm in Thm} tests for duplicates, before extending
-  the list. Deletion from the list works as follows:
-*}
-
-declare test[my_thms del]
-
-text {* After this, the theorem list is again: 
-
-  @{ML_response_fake [display,gray]
-  "MyThms.get @{context}"
-  "[\"True\"]"}
-
-  We used in this example two functions declared as @{ML_ind
-  declaration_attribute in Thm}, but there can be any number of them. We just
-  have to change the parser for reading the arguments accordingly.
-
-  \footnote{\bf FIXME What are: @{text "theory_attributes"}, @{text "proof_attributes"}?}
-
-  \begin{readmore}
-  FIXME: @{ML_file "Pure/more_thm.ML"}; parsers for attributes is in 
-  @{ML_file "Pure/Isar/attrib.ML"}...also explained in the chapter about
-  parsing.
-  \end{readmore}
-*}
-
-section {* Theories\label{sec:theories} (TBD) *}
-
-
-text {*
-  Theories are the most fundamental building blocks in Isabelle. They 
-  contain definitions, syntax declarations, axioms, proofs etc. If a definition
-  is stated, it must be stored in a theory in order to be usable later
-  on. Similar with proofs: once a proof is finished, the proved theorem
-  needs to be stored in the theorem database of the theory in order to
-  be usable. All relevant data of a theort can be querried as follows.
-
-  \begin{isabelle}
-  \isacommand{print\_theory}\\
-  @{text "> names: Pure Code_Generator HOL \<dots>"}\\
-  @{text "> classes: Inf < type \<dots>"}\\
-  @{text "> default sort: type"}\\
-  @{text "> syntactic types: #prop \<dots>"}\\
-  @{text "> logical types: 'a \<times> 'b \<dots>"}\\
-  @{text "> type arities: * :: (random, random) random \<dots>"}\\
-  @{text "> logical constants: == :: 'a \<Rightarrow> 'a \<Rightarrow> prop \<dots>"}\\
-  @{text "> abbreviations: \<dots>"}\\
-  @{text "> axioms: \<dots>"}\\
-  @{text "> oracles: \<dots>"}\\
-  @{text "> definitions: \<dots>"}\\
-  @{text "> theorems: \<dots>"}
-  \end{isabelle}
-
-  \begin{center}
-  \begin{tikzpicture}
-  \node[top color=white, bottom color=gray!30, draw=black!100, drop shadow] {A};
-  \end{tikzpicture}
-  \end{center}
-
-
-  In contrast to an ordinary theory, which simply consists of a type
-  signature, as well as tables for constants, axioms and theorems, a local
-  theory contains additional context information, such as locally fixed
-  variables and local assumptions that may be used by the package. The type
-  @{ML_type local_theory} is identical to the type of \emph{proof contexts}
-  @{ML_type "Proof.context"}, although not every proof context constitutes a
-  valid local theory.
-
-  @{ML "Context.>> o Context.map_theory"}
-
-  \footnote{\bf FIXME: list append in merge operations can cause 
-  exponential blowups.}
-*}
-
-section {* Setups (TBD) *}
-
-text {*
-  @{ML Sign.declare_const}
-
-  In the previous section we used \isacommand{setup} in order to make
-  a theorem attribute known to Isabelle. What happens behind the scenes
-  is that \isacommand{setup} expects a function of type 
-  @{ML_type "theory -> theory"}: the input theory is the current theory and the 
-  output the theory where the theory attribute has been stored.
-  
-  This is a fundamental principle in Isabelle. A similar situation occurs 
-  for example with declaring constants. The function that declares a 
-  constant on the ML-level is @{ML_ind  add_consts_i in Sign}. 
-  If you write\footnote{Recall that ML-code  needs to be 
-  enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} 
-*}  
-
-ML{*Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] @{theory} *}
-
-text {*
-  for declaring the constant @{text "BAR"} with type @{typ nat} and 
-  run the code, then you indeed obtain a theory as result. But if you 
-  query the constant on the Isabelle level using the command \isacommand{term}
-
-  \begin{isabelle}
-  \isacommand{term}~@{text [quotes] "BAR"}\\
-  @{text "> \"BAR\" :: \"'a\""}
-  \end{isabelle}
-
-  you do not obtain a constant of type @{typ nat}, but a free variable (printed in 
-  blue) of polymorphic type. The problem is that the ML-expression above did 
-  not register the declaration with the current theory. This is what the command
-  \isacommand{setup} is for. The constant is properly declared with
-*}
-
-setup %gray {* Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] *}
-
-text {* 
-  Now 
-  
-  \begin{isabelle}
-  \isacommand{term}~@{text [quotes] "BAR"}\\
-  @{text "> \"BAR\" :: \"nat\""}
-  \end{isabelle}
-
-  returns a (black) constant with the type @{typ nat}.
-
-  A similar command is \isacommand{local\_setup}, which expects a function
-  of type @{ML_type "local_theory -> local_theory"}. Later on we will also
-  use the commands \isacommand{method\_setup} for installing methods in the
-  current theory and \isacommand{simproc\_setup} for adding new simprocs to
-  the current simpset.
-*}
-
-section {* Contexts (TBD) *}
-
-section {* Local Theories (TBD) *}
-
-text {*
-  @{ML_ind "Local_Theory.declaration"}
-*}
-
-(*
-setup {*
- Sign.add_consts_i [(Binding"bar", @{typ "nat"},NoSyn)] 
-*}
-lemma "bar = (1::nat)"
-  oops
-
-setup {*   
-  Sign.add_consts_i [("foo", @{typ "nat"},NoSyn)] 
- #> PureThy.add_defs false [((@{binding "foo_def"}, 
-       Logic.mk_equals (Const ("FirstSteps.foo", @{typ "nat"}), @{term "1::nat"})), [])] 
- #> snd
-*}
-*)
-(*
-lemma "foo = (1::nat)"
-  apply(simp add: foo_def)
-  done
-
-thm foo_def
-*)
-
-
-section {* Pretty-Printing\label{sec:pretty} *}
-
-text {*
-  So far we printed out only plain strings without any formatting except for
-  occasional explicit line breaks using @{text [quotes] "\\n"}. This is
-  sufficient for ``quick-and-dirty'' printouts. For something more
-  sophisticated, Isabelle includes an infrastructure for properly formatting
-  text. Most of its functions do not operate on @{ML_type string}s, but on
-  instances of the pretty type:
-
-  @{ML_type_ind [display, gray] "Pretty.T"}
-
-  The function @{ML str in Pretty} transforms a (plain) string into such a pretty 
-  type. For example
-
-  @{ML_response_fake [display,gray]
-  "Pretty.str \"test\"" "String (\"test\", 4)"}
-
-  where the result indicates that we transformed a string with length 4. Once
-  you have a pretty type, you can, for example, control where linebreaks may
-  occur in case the text wraps over a line, or with how much indentation a
-  text should be printed.  However, if you want to actually output the
-  formatted text, you have to transform the pretty type back into a @{ML_type
-  string}. This can be done with the function @{ML_ind  string_of in Pretty}. In what
-  follows we will use the following wrapper function for printing a pretty
-  type:
-*}
-
-ML{*fun pprint prt = tracing (Pretty.string_of prt)*}
-
-text {*
-  The point of the pretty-printing infrastructure is to give hints about how to
-  layout text and let Isabelle do the actual layout. Let us first explain
-  how you can insert places where a line break can occur. For this assume the
-  following function that replicates a string n times:
-*}
-
-ML{*fun rep n str = implode (replicate n str) *}
-
-text {*
-  and suppose we want to print out the string:
-*}
-
-ML{*val test_str = rep 8 "fooooooooooooooobaaaaaaaaaaaar "*}
-
-text {*
-  We deliberately chose a large string so that it spans over more than one line. 
-  If we print out the string using the usual ``quick-and-dirty'' method, then
-  we obtain the ugly output:
-
-@{ML_response_fake [display,gray]
-"tracing test_str"
-"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
-ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
-aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
-oooooooooooooobaaaaaaaaaaaar"}
-
-  We obtain the same if we just use the function @{ML pprint}.
-
-@{ML_response_fake [display,gray]
-"pprint (Pretty.str test_str)"
-"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
-ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
-aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
-oooooooooooooobaaaaaaaaaaaar"}
-
-  However by using pretty types you have the ability to indicate possible
-  linebreaks for example at each whitespace. You can achieve this with the
-  function @{ML_ind breaks in Pretty}, which expects a list of pretty types
-  and inserts a possible line break in between every two elements in this
-  list. To print this list of pretty types as a single string, we concatenate
-  them with the function @{ML_ind blk in Pretty} as follows:
-
-@{ML_response_fake [display,gray]
-"let
-  val ptrs = map Pretty.str (space_explode \" \" test_str)
-in
-  pprint (Pretty.blk (0, Pretty.breaks ptrs))
-end"
-"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
-fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
-
-  Here the layout of @{ML test_str} is much more pleasing to the 
-  eye. The @{ML "0"} in @{ML_ind  blk in Pretty} stands for no hanging 
-  indentation of the printed string. You can increase the indentation 
-  and obtain
-  
-@{ML_response_fake [display,gray]
-"let
-  val ptrs = map Pretty.str (space_explode \" \" test_str)
-in
-  pprint (Pretty.blk (3, Pretty.breaks ptrs))
-end"
-"fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
-   fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
-
-  where starting from the second line the indent is 3. If you want
-  that every line starts with the same indent, you can use the
-  function @{ML_ind  indent in Pretty} as follows:
-
-@{ML_response_fake [display,gray]
-"let
-  val ptrs = map Pretty.str (space_explode \" \" test_str)
-in
-  pprint (Pretty.indent 10 (Pretty.blk (0, Pretty.breaks ptrs)))
-end"
-"          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
-          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
-          fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
-
-  If you want to print out a list of items separated by commas and 
-  have the linebreaks handled properly, you can use the function 
-  @{ML_ind  commas in Pretty}. For example
-
-@{ML_response_fake [display,gray]
-"let
-  val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
-in
-  pprint (Pretty.blk (0, Pretty.commas ptrs))
-end"
-"99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
-100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
-100016, 100017, 100018, 100019, 100020"}
-
-  where @{ML upto} generates a list of integers. You can print out this
-  list as a ``set'', that means enclosed inside @{text [quotes] "{"} and
-  @{text [quotes] "}"}, and separated by commas using the function
-  @{ML_ind  enum in Pretty}. For example
-*}
-
-text {*
-  
-@{ML_response_fake [display,gray]
-"let
-  val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
-in
-  pprint (Pretty.enum \",\" \"{\" \"}\" ptrs)
-end"
-"{99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
-  100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
-  100016, 100017, 100018, 100019, 100020}"}
-
-  As can be seen, this function prints out the ``set'' so that starting 
-  from the second, each new line has an indentation of 2.
-  
-  If you print out something that goes beyond the capabilities of the
-  standard functions, you can do relatively easily the formatting
-  yourself. Assume you want to print out a list of items where like in ``English''
-  the last two items are separated by @{text [quotes] "and"}. For this you can
-  write the function
-
-*}
-
-ML %linenosgray{*fun and_list [] = []
-  | and_list [x] = [x]
-  | and_list xs = 
-      let 
-        val (front, last) = split_last xs
-      in
-        (Pretty.commas front) @ 
-        [Pretty.brk 1, Pretty.str "and", Pretty.brk 1, last]
-      end *}
-
-text {*
-  where Line 7 prints the beginning of the list and Line
-  8 the last item. We have to use @{ML "Pretty.brk 1"} in order
-  to insert a space (of length 1) before the 
-  @{text [quotes] "and"}. This space is also a place where a line break 
-  can occur. We do the same after the @{text [quotes] "and"}. This gives you
-  for example
-
-@{ML_response_fake [display,gray]
-"let
-  val ptrs1 = map (Pretty.str o string_of_int) (1 upto 22)
-  val ptrs2 = map (Pretty.str o string_of_int) (10 upto 28)
-in
-  pprint (Pretty.blk (0, and_list ptrs1));
-  pprint (Pretty.blk (0, and_list ptrs2))
-end"
-"1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 
-and 22
-10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 and
-28"}
-
-  Next we like to pretty-print a term and its type. For this we use the
-  function @{text "tell_type"}.
-*}
-
-ML %linenosgray{*fun tell_type ctxt t = 
-let
-  fun pstr s = Pretty.breaks (map Pretty.str (space_explode " " s))
-  val ptrm = Pretty.quote (Syntax.pretty_term ctxt t)
-  val pty  = Pretty.quote (Syntax.pretty_typ ctxt (fastype_of t))
-in
-  pprint (Pretty.blk (0, 
-    (pstr "The term " @ [ptrm] @ pstr " has type " 
-      @ [pty, Pretty.str "."])))
-end*}
-
-text {*
-  In Line 3 we define a function that inserts possible linebreaks in places
-  where a space is. In Lines 4 and 5 we pretty-print the term and its type
-  using the functions @{ML_ind  pretty_term in Syntax} and @{ML_ind 
-  pretty_typ in Syntax}. We also use the function @{ML_ind quote in
-  Pretty} in order to enclose the term and type inside quotation marks. In
-  Line 9 we add a period right after the type without the possibility of a
-  line break, because we do not want that a line break occurs there.
-  Now you can write
-
-  @{ML_response_fake [display,gray]
-  "tell_type @{context} @{term \"min (Suc 0)\"}"
-  "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."}
-  
-  To see the proper line breaking, you can try out the function on a bigger term 
-  and type. For example:
-
-  @{ML_response_fake [display,gray]
-  "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}"
-  "The term \"op = (op = (op = (op = (op = op =))))\" has type 
-\"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."}
-
-  The function @{ML_ind big_list in Pretty} helps with printing long lists.
-  It is used for example in the command \isacommand{print\_theorems}. An
-  example is as follows.
-
-  @{ML_response_fake [display,gray]
-  "let
-  val pstrs = map (Pretty.str o string_of_int) (4 upto 10)
-in
-  pprint (Pretty.big_list \"header\" pstrs)
-end"
-  "header
-  4
-  5
-  6
-  7
-  8
-  9
-  10"}
-
-  Like @{ML blk in Pretty}, the function @{ML_ind chunks in Pretty} prints out 
-  a list of items, but automatically inserts forced breaks between each item.
-  Compare
-
-  @{ML_response_fake [display,gray]
-  "let
-  val a_and_b = [Pretty.str \"a\", Pretty.str \"b\"]
-in
-  pprint (Pretty.blk (0, a_and_b));
-  pprint (Pretty.chunks a_and_b)
-end"
-"ab
-a
-b"}
-  
-  \footnote{\bf FIXME: What happens with printing big formulae?}
-
-  
-
-  \begin{readmore}
-  The general infrastructure for pretty-printing is implemented in the file
-  @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"}
-  contains pretty-printing functions for terms, types, theorems and so on.
-  
-  @{ML_file "Pure/General/markup.ML"}
-  \end{readmore}
-*}
-
-(*
-text {*
-  printing into the goal buffer as part of the proof state
-*}
-
-text {* writing into the goal buffer *}
-
-ML {* fun my_hook interactive state =
-         (interactive ? Proof.goal_message (fn () => Pretty.str  
-"foo")) state
-*}
-
-setup %gray {* Context.theory_map (Specification.add_theorem_hook my_hook) *}
-
-lemma "False"
-oops
-*)
-
-(*
-ML {*
-fun setmp_show_all_types f =
-   setmp show_all_types
-         (! show_types orelse ! show_sorts orelse ! show_all_types) f;
-
-val ctxt = @{context};
-val t1 = @{term "undefined::nat"};
-val t2 = @{term "Suc y"};
-val pty =        Pretty.block (Pretty.breaks
-             [(setmp show_question_marks false o setmp_show_all_types)
-                  (Syntax.pretty_term ctxt) t1,
-              Pretty.str "=", Syntax.pretty_term ctxt t2]);
-pty |> Pretty.string_of  
-*}
-
-text {* the infrastructure of Syntax-pretty-term makes sure it is printed nicely  *}
-
-
-ML {* Pretty.mark Markup.hilite (Pretty.str "foo") |> Pretty.string_of  |> tracing *}
-ML {* (Pretty.str "bar") |> Pretty.string_of |> tracing *}
-*)
-
-section {* Morphisms (TBD) *}
-
-text {*
-  Morphisms are arbitrary transformations over terms, types, theorems and bindings.
-  They can be constructed using the function @{ML_ind morphism in Morphism},
-  which expects a record with functions of type
-
-  \begin{isabelle}
-  \begin{tabular}{rl}
-  @{text "binding:"} & @{text "binding -> binding"}\\
-  @{text "typ:"}     & @{text "typ -> typ"}\\
-  @{text "term:"}    & @{text "term -> term"}\\
-  @{text "fact:"}    & @{text "thm list -> thm list"}
-  \end{tabular}
-  \end{isabelle}
-
-  The simplest morphism is the  @{ML_ind identity in Morphism}-morphism defined as
-*}
-
-ML{*val identity = Morphism.morphism {binding = I, typ = I, term = I, fact = I}*}
-  
-text {*
-  Morphisms can be composed with the function @{ML_ind "$>" in Morphism}
-*}
-
-ML{*fun trm_phi (Free (x, T)) = Var ((x, 0), T) 
-  | trm_phi (Abs (x, T, t)) = Abs (x, T, trm_phi t)
-  | trm_phi (t $ s) = (trm_phi t) $ (trm_phi s)
-  | trm_phi t = t*}
-
-ML{*val phi = Morphism.term_morphism trm_phi*}
-
-ML{*Morphism.term phi @{term "P x y"}*}
-
-text {*
-  @{ML_ind term_morphism in Morphism}
-
-  @{ML_ind term in Morphism},
-  @{ML_ind thm in Morphism}
-
-  \begin{readmore}
-  Morphisms are implemented in the file @{ML_file "Pure/morphism.ML"}.
-  \end{readmore}
-*}
-
-section {* Misc (TBD) *}
-
-ML {*Datatype.get_info @{theory} "List.list"*}
-
-text {* 
-FIXME: association lists:
-@{ML_file "Pure/General/alist.ML"}
-
-FIXME: calling the ML-compiler
-
-*}
-
-
-
-section {* Managing Name Spaces (TBD) *}
-
-ML {* Sign.intern_type @{theory} "list" *}
-ML {* Sign.intern_const @{theory} "prod_fun" *}
-
-
-text {* 
-  @{ML_ind "Binding.str_of"} returns the string with markup;
-  @{ML_ind "Binding.name_of"} returns the string without markup
-
-  @{ML_ind "Binding.conceal"} 
-*}
-
-section {* Concurrency (TBD) *}
-
-text {*
-  @{ML_ind prove_future in Goal}
-  @{ML_ind future_result in Goal}
-  @{ML_ind fork_pri in Future}
-*}
-
-section {* Summary *}
-
-text {*
-  \begin{conventions}
-  \begin{itemize}
-  \item Start with a proper context and then pass it around 
-  through all your functions.
-  \end{itemize}
-  \end{conventions}
-*}
-
-end
--- a/ProgTutorial/ROOT.ML	Thu Nov 19 14:11:50 2009 +0100
+++ b/ProgTutorial/ROOT.ML	Thu Nov 19 17:48:44 2009 +0100
@@ -5,7 +5,8 @@
 
 use_thy "Intro";
 use_thy "FirstSteps";
-use_thy "General";
+use_thy "Essential";
+use_thy "Advanced";
 
 no_document use_thy "Helper/Command/Command";
 use_thy "Parsing";
Binary file progtutorial.pdf has changed