ProgTutorial/Advanced.thy
changeset 486 45cfd2ece7bd
parent 485 f3536f0b47a9
child 487 1c4250bc6258
equal deleted inserted replaced
485:f3536f0b47a9 486:45cfd2ece7bd
    30   other hand, store local data for a task at hand. They act like the
    30   other hand, store local data for a task at hand. They act like the
    31   ``short-term memory'' and there can be many of them that are active in
    31   ``short-term memory'' and there can be many of them that are active in
    32   parallel.
    32   parallel.
    33 *}
    33 *}
    34 
    34 
    35 section {* Theories\label{sec:theories} (TBD) *}
    35 section {* Theories and Setups\label{sec:theories} *}
    36 
    36 
    37 text {*
    37 text {*
    38   Theories, as said above, are the most basic layer in Isabelle. They contain
    38   Theories, as said above, are the most basic layer of abstraction in
    39   definitions, syntax declarations, axioms, proofs etc. If a definition is
    39   Isabelle. They contain definitions, syntax declarations, axioms, proofs
    40   stated, it must be stored in a theory in order to be usable later
    40   and much more. If a definition is made, it must be stored in a theory in order to be
    41   on. Similar with proofs: once a proof is finished, the proved theorem needs
    41   usable later on. Similar with proofs: once a proof is finished, the proved
    42   to be stored in the theorem database of the theory in order to be
    42   theorem needs to be stored in the theorem database of the theory in order to
    43   usable. All relevant data of a theory can be queried as follows.
    43   be usable. All relevant data of a theory can be queried as follows.
    44 
    44 
    45   \begin{isabelle}
    45   \begin{isabelle}
    46   \isacommand{print\_theory}\\
    46   \isacommand{print\_theory}\\
    47   @{text "> names: Pure Code_Generator HOL \<dots>"}\\
    47   @{text "> names: Pure Code_Generator HOL \<dots>"}\\
    48   @{text "> classes: Inf < type \<dots>"}\\
    48   @{text "> classes: Inf < type \<dots>"}\\
    56   @{text "> oracles: \<dots>"}\\
    56   @{text "> oracles: \<dots>"}\\
    57   @{text "> definitions: \<dots>"}\\
    57   @{text "> definitions: \<dots>"}\\
    58   @{text "> theorems: \<dots>"}
    58   @{text "> theorems: \<dots>"}
    59   \end{isabelle}
    59   \end{isabelle}
    60 
    60 
    61 
    61   In the context ML-programming, the most important command with theories
    62 
    62   is \isacommand{setup}. In the previous chapters we used it, for
    63   \begin{center}
    63   example, to make a theorem attribute known to Isabelle or to register a theorem
    64   \begin{tikzpicture}
    64   under a name. What happens behind the scenes is that \isacommand{setup}
    65   \node[top color=white, bottom color=gray!30, draw=black!100, drop shadow] {A};
    65   expects a function of type @{ML_type "theory -> theory"}: the input theory
    66   \end{tikzpicture}
    66   is the current theory and the output the theory where the attribute has been
    67   \end{center}
    67   registered or the theorem has been stored.  This is a fundamental principle
    68 
    68   in Isabelle. A similar situation arises with declaring constants. The
    69   \footnote{\bf FIXME: list append in merge operations can cause 
    69   function that declares a constant on the ML-level is @{ML_ind declare_const
    70   exponential blowups.}
    70   in Sign} in the structure @{ML_struct Sign}. To see how \isacommand{setup}
    71 *}
    71   works, consider the following code: 
    72 
       
    73 section {* Setups (TBD) *}
       
    74 
       
    75 text {*
       
    76   In the previous section we used \isacommand{setup} in order, for example, 
       
    77   to make a theorem attribute known to Isabelle or register a theorem under
       
    78   a name. What happens behind the scenes is that \isacommand{setup} expects a 
       
    79   function of type @{ML_type "theory -> theory"}: the input theory is the current
       
    80   theory and the output the theory where the theory attribute or theorem has been
       
    81   stored.
       
    82 
       
    83   This is a fundamental principle in Isabelle. A similar situation arises
       
    84   with declaring constants. The function that declares a 
       
    85   constant on the ML-level is @{ML_ind  declare_const in Sign}. 
       
    86   However, note that if you simply write\footnote{Recall that ML-code  needs to be 
       
    87   enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} 
       
    88 *}  
    72 *}  
    89 
    73 
    90 ML{*let
    74 ML{*let
    91   val thy = @{theory}
    75   val thy = @{theory}
    92   val bar_const = ((@{binding "BAR"}, @{typ "nat"}), NoSyn)
    76   val bar_const = ((@{binding "BAR"}, @{typ "nat"}), NoSyn)
    93 in 
    77 in 
    94   Sign.declare_const @{context} bar_const thy  
    78   Sign.declare_const @{context} bar_const thy  
    95 end*}
    79 end*}
    96 
    80 
    97 text {*
    81 text {*
    98   with the intention of declaring the constant @{text "BAR"} with type @{typ nat} 
    82   If you simply write this code\footnote{Recall that ML-code needs to be enclosed in
    99   and  run the code, then indeed you obtain a theory as result. But if you 
    83   \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} with the
   100   query the constant on the Isabelle level using the command \isacommand{term}
    84   intention of declaring a constant @{text "BAR"} with type @{typ nat} and run
       
    85   the code, then indeed you obtain a theory as result. But if you query the
       
    86   constant on the Isabelle level using the command \isacommand{term}
   101 
    87 
   102   \begin{isabelle}
    88   \begin{isabelle}
   103   \isacommand{term}~@{text BAR}\\
    89   \isacommand{term}~@{text BAR}\\
   104   @{text "> \"BAR\" :: \"'a\""}
    90   @{text "> \"BAR\" :: \"'a\""}
   105   \end{isabelle}
    91   \end{isabelle}
   109   ML-expression above did not ``register'' the declaration with the current theory. 
    95   ML-expression above did not ``register'' the declaration with the current theory. 
   110   This is what the command \isacommand{setup} is for. The constant is properly 
    96   This is what the command \isacommand{setup} is for. The constant is properly 
   111   declared with
    97   declared with
   112 *}
    98 *}
   113 
    99 
   114 setup %gray {* let
   100 setup %gray {* fn thy => 
       
   101 let
   115   val bar_const = ((@{binding "BAR"}, @{typ "nat"}), NoSyn)
   102   val bar_const = ((@{binding "BAR"}, @{typ "nat"}), NoSyn)
       
   103   val (_, thy') = Sign.declare_const @{context} bar_const thy
   116 in 
   104 in 
   117   Sign.declare_const @{context} bar_const #> snd 
   105   thy'
   118 end *}
   106 end *}
   119 
   107 
   120 text {* 
   108 text {* 
   121   where the declaration is actually applied to the theory and
   109   where the declaration is actually applied to the current theory and
   122   
   110   
   123   \begin{isabelle}
   111   \begin{isabelle}
   124   \isacommand{term}~@{text [quotes] "BAR"}\\
   112   \isacommand{term}~@{text [quotes] "BAR"}\\
   125   @{text "> \"BAR\" :: \"nat\""}
   113   @{text "> \"BAR\" :: \"nat\""}
   126   \end{isabelle}
   114   \end{isabelle}
   127 
   115 
   128   returns a (black) constant with the type @{typ nat}, as expected.
   116   returns now a (black) constant with the type @{typ nat}, as expected.
   129 
   117 
   130   In a sense, \isacommand{setup} can be seen as a transaction that takes the
   118   In a sense, \isacommand{setup} can be seen as a transaction that takes the
   131   current theory, applies an operation, and produces a new current theory. This
   119   current theory, applies an operation, and produces a new current theory. This
   132   means that we have to be careful to apply operations always to the current
   120   means that we have to be careful to apply operations always to the most current
   133   theory, not to a \emph{stale} one. The code below produces
   121   theory, not to a \emph{stale} one. Consider again the function inside the
   134 
   122   \isacommand{setup}-command:
   135 
   123 
   136   A similar command is \isacommand{local\_setup}, which expects a function
   124   \begin{isabelle}
   137   of type @{ML_type "local_theory -> local_theory"}. Later on we will also
   125   \begin{graybox}
   138   use the commands \isacommand{method\_setup} for installing methods in the
   126   \isacommand{setup}~@{text "\<verbopen>"} @{ML
   139   current theory and \isacommand{simproc\_setup} for adding new simprocs to
   127 "fn thy => 
   140   the current simpset.
   128 let
       
   129   val bar_const = ((@{binding \"BAR\"}, @{typ \"nat\"}), NoSyn)
       
   130   val (_, thy') = Sign.declare_const @{context} bar_const thy
       
   131 in
       
   132   thy
       
   133 end"}~@{text "\<verbclose>"}\isanewline
       
   134   @{text "> ERROR \"Stale theory encountered\""}
       
   135   \end{graybox}
       
   136   \end{isabelle}
       
   137 
       
   138   This time we erroneously return the original theory @{text thy}, instead of
       
   139   the modified one @{text thy'}. Such programming errors with handling the
       
   140   most current theory will always result into stale theory error messages.
       
   141 
       
   142   However, sometimes it does make sense to work with two theories at the same
       
   143   time, especially in the context of parsing and typing. In the code below we
       
   144   use in Line 3 the function @{ML_ind copy in Theory} from the structure
       
   145   @{ML_struct Theory} for obtaining a new theory that contains the same
       
   146   data, but is unrelated to the existing theory.
       
   147 *}
       
   148 
       
   149 setup %graylinenos {* fn thy => 
       
   150 let
       
   151   val tmp_thy = Theory.copy thy
       
   152   val foo_const = ((@{binding "FOO"}, @{typ "nat => nat"}), NoSyn)
       
   153   val (_, tmp_thy') = Sign.declare_const @{context} foo_const tmp_thy
       
   154   val trm1 = Syntax.read_term_global tmp_thy' "FOO baz"
       
   155   val trm2 = Syntax.read_term_global thy "FOO baz"
       
   156   val _ = writeln (@{make_string} trm1 ^ "\n" ^ @{make_string} trm2)
       
   157 in
       
   158   thy
       
   159 end *}
       
   160 
       
   161 text {*
       
   162   That means we can make changes to the theory @{text tmp_thy} without
       
   163   affecting the current theory @{text thy}. In this case we declare in @{text
       
   164   "tmp_thy"} the constant @{text FOO} (Lines 4 and 5). The point of this code
       
   165   is that we next, in Lines 6 and 7, parse a string to become a term (both
       
   166   times the string is @{text [quotes] "FOO baz"}). But since we parse the string
       
   167   once in the context of the theory @{text tmp_thy'} in which @{text FOO} is
       
   168   declared to be a constant of type @{typ "nat \<Rightarrow>nat"} and once in the context 
       
   169   of @{text thy}, we obtain two different terms, namely 
       
   170 
       
   171   \begin{isabelle}
       
   172   \begin{graybox}
       
   173   @{text "> Const (\"Advanced.FOO\", \"nat \<Rightarrow> nat\") $ Free (\"baz\", \"nat\")"}\isanewline
       
   174   @{text "> Free (\"FOO\", \"'a \<Rightarrow> 'b\") $ Free (\"baz\", \"'a\")"}
       
   175   \end{graybox}
       
   176   \end{isabelle}
       
   177 
       
   178   There are two reasons for parsing a term in a temporary theory. One is to
       
   179   obtain fully qualified names and the other is appropriate type inference.
       
   180   This is relevant in situations where definitions are made later, but parsing
       
   181   and type inference has to take already proceed as if the definitions were
       
   182   already made.
   141 *}
   183 *}
   142 
   184 
   143 section {* Contexts (TBD) *}
   185 section {* Contexts (TBD) *}
   144 
   186 
   145 ML{*Proof_Context.debug*}
   187 text {*
   146 ML{*Proof_Context.verbose*}
   188   Contexts are arguably more important than theories, even though they only 
       
   189   contain ``short-term memory data''. The reason is that a vast number of
       
   190   functions in Isabelle depend one way or the other on contexts. Even such
       
   191   mundane operation like printing out a term make essential use of contexts.
       
   192 *}
       
   193 
       
   194 (*
       
   195 ML{*Proof_Context.debug := true*}
       
   196 ML{*Proof_Context.verbose := true*}
       
   197 *)
       
   198 
       
   199 lemma "True"
       
   200 proof -
       
   201   { -- "\<And>x. _"
       
   202     fix x
       
   203     have "B x" sorry
       
   204     thm this
       
   205   }
       
   206 
       
   207   thm this
       
   208 
       
   209   { -- "A \<Longrightarrow> _"
       
   210     assume A
       
   211     have B sorry
       
   212     thm this
       
   213   }
       
   214    
       
   215   thm this
       
   216 
       
   217   { -- "\<And>x. x = _ \<Longrightarrow> _"
       
   218     def x \<equiv> a
       
   219     have "B x" sorry
       
   220   }
       
   221 
       
   222   thm this
       
   223 
       
   224 oops
   147 
   225 
   148 
   226 
   149 section {* Local Theories (TBD) *}
   227 section {* Local Theories (TBD) *}
   150 
   228 
   151 text {*
   229 text {*
   157   @{ML_type "Proof.context"}, although not every proof context constitutes a
   235   @{ML_type "Proof.context"}, although not every proof context constitutes a
   158   valid local theory.
   236   valid local theory.
   159 
   237 
   160   @{ML "Context.>> o Context.map_theory"}
   238   @{ML "Context.>> o Context.map_theory"}
   161   @{ML_ind "Local_Theory.declaration"}
   239   @{ML_ind "Local_Theory.declaration"}
   162 *}
   240 
   163 
   241    A similar command is \isacommand{local\_setup}, which expects a function
   164 (*
   242   of type @{ML_type "local_theory -> local_theory"}. Later on we will also
   165 setup {*
   243   use the commands \isacommand{method\_setup} for installing methods in the
   166  Sign.add_consts_i [(Binding"bar", @{typ "nat"},NoSyn)] 
   244   current theory and \isacommand{simproc\_setup} for adding new simprocs to
   167 *}
   245   the current simpset.
   168 lemma "bar = (1::nat)"
   246 *}
   169   oops
   247 
   170 
       
   171 setup {*   
       
   172   Sign.add_consts_i [("foo", @{typ "nat"},NoSyn)] 
       
   173  #> PureThy.add_defs false [((@{binding "foo_def"}, 
       
   174        Logic.mk_equals (Const ("FirstSteps.foo", @{typ "nat"}), @{term "1::nat"})), [])] 
       
   175  #> snd
       
   176 *}
       
   177 *)
       
   178 (*
       
   179 lemma "foo = (1::nat)"
       
   180   apply(simp add: foo_def)
       
   181   done
       
   182 
       
   183 thm foo_def
       
   184 *)
       
   185 
   248 
   186 section {* Morphisms (TBD) *}
   249 section {* Morphisms (TBD) *}
   187 
   250 
   188 text {*
   251 text {*
   189   Morphisms are arbitrary transformations over terms, types, theorems and bindings.
   252   Morphisms are arbitrary transformations over terms, types, theorems and bindings.