CookBook/FirstSteps.thy
changeset 12 2f1736cb8f26
parent 11 733614e236a3
child 13 2b07da8b310d
equal deleted inserted replaced
11:733614e236a3 12:2f1736cb8f26
     1 theory FirstSteps
     1 theory FirstSteps
     2 imports Main
     2 imports Main
     3 uses "antiquote_setup.ML"
     3 uses "antiquote_setup.ML"
     4      ("comp_simproc")
       
     5 begin
     4 begin
     6 
     5 
     7 
     6 
     8 (*<*)
     7 (*<*)
       
     8 
     9 
     9 
    10 ML {*
    10 ML {*
    11 local structure O = ThyOutput
    11 local structure O = ThyOutput
    12 in
    12 in
    13   fun check_exists f = 
    13   fun check_exists f = 
    64   then Isabelle's undo operation has no effect on the definition of 
    64   then Isabelle's undo operation has no effect on the definition of 
    65   @{ML "foo"}. 
    65   @{ML "foo"}. 
    66 
    66 
    67   During developments you might find it necessary to quickly inspect some data
    67   During developments you might find it necessary to quickly inspect some data
    68   in your code. This can be done in a ``quick-and-dirty'' fashion using 
    68   in your code. This can be done in a ``quick-and-dirty'' fashion using 
    69   the function @{ML "warning"}. For example
    69   the function @{ML "warning"}. For example 
    70 *}
    70 *}
    71 
    71 
    72 ML {*
    72 ML {*
    73   val _ = warning "any string"
    73   val _ = warning "any string"
    74 *}
    74 *}
    75 
    75 
    76 text {*
    76 text {*
    77   will print out the string inside the response buffer of Isabelle.
    77   will print out @{ML "\"any string\""} inside the response buffer of Isabelle.
    78 *}
    78   PolyML provides a convenient, though quick-and-dirty, method for converting 
    79 
    79   arbitrary values into strings, for example: 
       
    80 *}
       
    81 
       
    82 ML {*
       
    83   val _ = warning (makestring 1)
       
    84 *}
       
    85 
       
    86 text {*
       
    87   However this only works if the type of what is printed is monomorphic and not 
       
    88   a function.
       
    89 *}
       
    90 
       
    91 text {* (FIXME: add comment about including ML-files) *}
    80 
    92 
    81 
    93 
    82 section {* Antiquotations *}
    94 section {* Antiquotations *}
    83 
    95 
    84 text {*
    96 text {*
    92 ML {* Context.theory_name @{theory} *}
   104 ML {* Context.theory_name @{theory} *}
    93 
   105 
    94 text {* 
   106 text {* 
    95   where @{text "@{theory}"} is an antiquotation that is substituted with the
   107   where @{text "@{theory}"} is an antiquotation that is substituted with the
    96   current theory (remember that we assumed we are inside the theory CookBook). 
   108   current theory (remember that we assumed we are inside the theory CookBook). 
    97   The name of this theory can be extrated using a the function @{ML "Context.theory_name"}. 
   109   The name of this theory can be extrated using the function @{ML "Context.theory_name"}. 
    98   So the code above returns the string @{ML "\"CookBook\""}.
   110   So the code above returns the string @{ML "\"CookBook\""}.
    99 
   111 
   100   Note, however, that antiquotations are statically scoped, that is the value is
   112   Note, however, that antiquotations are statically scoped, that is the value is
   101   determined at ``compile-time'' not ``run-time''. For example the function
   113   determined at ``compile-time'', not ``run-time''. For example the function
   102 
   114 
   103 *}
   115 *}
   104 
   116 
   105 ML {* 
   117 ML {* 
   106   fun current_thyname () = Context.theory_name @{theory}
   118   fun current_thyname () = Context.theory_name @{theory}
   123 
   135 
   124 text {*
   136 text {*
   125   In the course of this introduction, we will learn more about 
   137   In the course of this introduction, we will learn more about 
   126   these antoquotations: they greatly simplify Isabelle programming since one
   138   these antoquotations: they greatly simplify Isabelle programming since one
   127   can directly access all kinds of logical elements from ML.
   139   can directly access all kinds of logical elements from ML.
       
   140 
   128 *}
   141 *}
   129 
   142 
   130 section {* Terms *}
   143 section {* Terms *}
   131 
   144 
   132 text {*
   145 text {*
   139 text {*
   152 text {*
   140   This will show the term @{term "(a::nat) + b = c"}, but printed out using the internal
   153   This will show the term @{term "(a::nat) + b = c"}, but printed out using the internal
   141   representation of this term. This internal represenation corresponds to the 
   154   representation of this term. This internal represenation corresponds to the 
   142   datatype defined in @{ML_file "Pure/term.ML"}.
   155   datatype defined in @{ML_file "Pure/term.ML"}.
   143   
   156   
   144   The internal representation of terms uses the usual de-Bruijn indices mechanism where bound 
   157   The internal representation of terms uses the usual de-Bruijn index mechanism where bound 
   145   variables are represented by the constructor @{ML Bound}. The index in @{ML Bound} refers to
   158   variables are represented by the constructor @{ML Bound}. The index in @{ML Bound} refers to
   146   the number of Abstractions (@{ML Abs}) we have to skip until we hit the @{ML Abs} that
   159   the number of Abstractions (@{ML Abs}) we have to skip until we hit the @{ML Abs} that
   147   binds the corresponding variable. However, the names of bound variables are 
   160   binds the corresponding variable. However, in Isabelle the names of bound variables are 
   148   kept at abstractions for printing purposes, and so should be treated only as comments. 
   161   kept at abstractions for printing purposes, and so should be treated only as comments. 
   149 
   162 
   150   \begin{readmore}
   163   \begin{readmore}
   151   Terms are described in detail in \ichcite{ch:logic}. Their
   164   Terms are described in detail in \ichcite{ch:logic}. Their
   152   definition and many useful operations can be found in @{ML_file "Pure/term.ML"}.
   165   definition and many useful operations can be found in @{ML_file "Pure/term.ML"}.
   153   \end{readmore}
   166   \end{readmore}
   154 
   167 
   155   Sometimes the internal representation can be surprisingly different
   168   Sometimes the internal representation can be surprisingly different
   156   from what you see at the user level, because the layer of
   169   from what you see at the user level, because the layers of
   157   parsing/type checking/pretty printing can be quite elaborate. 
   170   parsing/type checking/pretty printing can be quite elaborate. 
   158 
   171 
   159   \begin{exercise}
   172   \begin{exercise}
   160   Look at the internal term representation of the following terms, and
   173   Look at the internal term representation of the following terms, and
   161   find out why they are represented like this.
   174   find out why they are represented like this.
   168 
   181 
   169   Hint: The third term is already quite big, and the pretty printer
   182   Hint: The third term is already quite big, and the pretty printer
   170   may omit parts of it by default. If you want to see all of it, you
   183   may omit parts of it by default. If you want to see all of it, you
   171   can use @{ML "print_depth 50"} to set the limit to a value high enough.
   184   can use @{ML "print_depth 50"} to set the limit to a value high enough.
   172   \end{exercise}
   185   \end{exercise}
   173 *}
   186 
   174 
   187   The anti-quotation @{text "@prop"} constructs terms of proposition type, 
   175 ML {*
   188   inserting the invisible @{text "Trueprop"} coercion when necessary. 
   176   @{const_name plus}
   189   Consider for example
   177 *}
   190 
   178 
   191 *}
   179 ML {*
   192 
   180   @{term "{ [x::int] | x. x \<le> -2 }"}
   193 ML {* @{term "P x"} *}
   181 *}
   194 
   182 
   195 ML {* @{prop "P x"} *}
   183 text {*
   196 
   184   The internal names of constants like @{term "zero"} or @{text "+"} are
   197 text {* and *}
       
   198 
       
   199 
       
   200 ML {* @{term "P x \<Longrightarrow> Q x"} *}
       
   201 
       
   202 ML {* @{prop "P x \<Longrightarrow> Q x"} *}
       
   203 
       
   204 section {* Construting Terms Manually *} 
       
   205 
       
   206 text {*
       
   207 
       
   208   While antiquotations are very convenient for constructing terms, they can
       
   209   only construct fixed terms. However, one often needs to construct terms dynamially. 
       
   210   For example in order to write the function that returns the implication 
       
   211   @{term "\<And>x. P x \<Longrightarrow> Q x"} taking @{term P} and @{term Q} as arguments, one can 
       
   212   only write
       
   213 *}
       
   214 
       
   215 
       
   216 ML {*
       
   217   fun make_PQ_imp P Q =
       
   218   let
       
   219     val nat = HOLogic.natT
       
   220     val x = Free ("x", nat)
       
   221   in Logic.all x (Logic.mk_implies (HOLogic.mk_Trueprop (P $ x),
       
   222                                     HOLogic.mk_Trueprop (Q $ x)))
       
   223   end
       
   224 *}
       
   225 
       
   226 text {*
       
   227 
       
   228   The reason is that one cannot pass the arguments @{term P} and @{term Q} into 
       
   229   an antiquotation. 
       
   230 *}
       
   231 
       
   232 text {*
       
   233 
       
   234    The internal names of constants like @{term "zero"} or @{text "+"} are
   185   often more complex than one first expects. Here, the extra prefixes
   235   often more complex than one first expects. Here, the extra prefixes
   186   @{text zero_class} and @{text plus_class} are present because the
   236   @{text zero_class} and @{text plus_class} are present because the
   187   constants are defined within a type class. Guessing such internal
   237   constants are defined within a type class. Guessing such internal
   188   names can be extremely hard, which is why the system provides
   238   names can be extremely hard, which is why the system provides
   189   another antiquotation: @{ML "@{const_name plus}"} gives just this
   239   another antiquotation: @{ML "@{const_name plus}"} gives just this
   190   name.
   240   name. For example 
   191 
   241 
   192   FIXME: maybe explain @{text "@{prop \<dots>}"} as a special kind of terms 
   242 *}
   193 *}
   243 
   194 
   244 ML {* @{const_name plus} *}
   195 ML {* @{prop "True"} *}
   245 
   196 
   246 text {* produes the fully qualyfied name of the constant plus. *}
   197 
   247 
   198 
   248 
   199 section {* Possible Section on Construting Explicitly Terms *} 
   249 
   200 
   250 
   201 text {*
   251 text {*
   202 
   252 
   203   There is a disadvantage of using the @{text "@{term \<dots>}"} antiquotation
   253   There are many funtions in @{ML_file "Pure/logic.ML"} and
   204   directly in order to construct terms. 
   254   @{ML_file "HOL/hologic.ML"} that make such manual constructions of terms 
   205 *}
   255   easier. Have a look ther and try to solve the following exercises:
   206 
       
   207 ML {*
       
   208 
       
   209   val nat = HOLogic.natT
       
   210   val x = Free ("x", nat)
       
   211   val t = Free ("t", nat)
       
   212   val P = Free ("P", nat --> HOLogic.boolT)
       
   213   val Q = Free ("Q", nat --> HOLogic.boolT)
       
   214 
       
   215   val A1 = Logic.all x 
       
   216            (Logic.mk_implies (HOLogic.mk_Trueprop (P $ x),
       
   217                               HOLogic.mk_Trueprop (Q $ x)))
       
   218            
       
   219 
       
   220   val A2 = HOLogic.mk_Trueprop (P $ t)
       
   221 
   256 
   222 *}
   257 *}
   223 
   258 
   224 text {*
   259 text {*
   225 
   260 
   227   Write a function @{ML_text "rev_sum : term -> term"} that takes a
   262   Write a function @{ML_text "rev_sum : term -> term"} that takes a
   228   term of the form @{text "t\<^isub>1 + t\<^isub>2 + \<dots> + t\<^isub>n"} (whereby @{text "i"} might be zero)
   263   term of the form @{text "t\<^isub>1 + t\<^isub>2 + \<dots> + t\<^isub>n"} (whereby @{text "i"} might be zero)
   229   and returns the reversed sum @{text "t\<^isub>n + \<dots> + t\<^isub>2 + t\<^isub>1"}. Assume
   264   and returns the reversed sum @{text "t\<^isub>n + \<dots> + t\<^isub>2 + t\<^isub>1"}. Assume
   230   the @{text "t\<^isub>i"} can be arbitrary expressions and also note that @{text "+"} 
   265   the @{text "t\<^isub>i"} can be arbitrary expressions and also note that @{text "+"} 
   231   associates to the left. Try your function on some examples, and see if 
   266   associates to the left. Try your function on some examples, and see if 
   232   the result typechecks. (FIXME: clash with the type-checking section later)
   267   the result typechecks. 
   233   \end{exercise}
   268   \end{exercise}
   234 *}
   269 *}
   235 
   270 
   236 ML {* 
   271 ML {* 
   237   fun rev_sum t =
   272   fun rev_sum t =
   257   fun make_sum t1 t2 =
   292   fun make_sum t1 t2 =
   258       HOLogic.mk_nat (HOLogic.dest_nat t1 + HOLogic.dest_nat t2)
   293       HOLogic.mk_nat (HOLogic.dest_nat t1 + HOLogic.dest_nat t2)
   259 *}
   294 *}
   260 
   295 
   261 
   296 
   262 text {*
       
   263   \begin{exercise}
       
   264   Look at the functions defined in @{ML_file "Pure/logic.ML"} and
       
   265   @{ML_file "HOL/hologic.ML"} and see if they can make your life
       
   266   easier.
       
   267   \end{exercise}
       
   268 *}
       
   269 
       
   270 
   297 
   271 section {* Type checking *}
   298 section {* Type checking *}
   272 
   299 
   273 text {* 
   300 text {* 
   274   We can freely construct and manipulate terms, since they are just
   301   We can freely construct and manipulate terms, since they are just
   280   Unlike @{ML_type term}s, which are just trees, @{ML_type
   307   Unlike @{ML_type term}s, which are just trees, @{ML_type
   281   "cterm"}s are abstract objects that are guaranteed to be
   308   "cterm"}s are abstract objects that are guaranteed to be
   282   type-correct, and can only be constructed via the official
   309   type-correct, and can only be constructed via the official
   283   interfaces.
   310   interfaces.
   284 
   311 
   285   (FIXME: Alex what do you mean concretely by ``official interfaces'')
       
   286 
       
   287   Type checking is always relative to a theory context. For now we can use
   312   Type checking is always relative to a theory context. For now we can use
   288   the @{ML "@{theory}"} antiquotation to get hold of the current theory.
   313   the @{ML "@{theory}"} antiquotation to get hold of the current theory.
   289   For example we can write:
   314   For example we can write:
   290 *}
   315 *}
   291 
   316 
   292 ML {* cterm_of @{theory} @{term "(a::nat) + b = c"} *}
   317 ML {* cterm_of @{theory} @{term "(a::nat) + b = c"} *}
       
   318 
       
   319 ML {*
       
   320   let
       
   321     val natT = @{typ "nat"}
       
   322     val zero = @{term "0::nat"}
       
   323   in
       
   324     cterm_of @{theory} 
       
   325         (Const (@{const_name plus}, natT --> natT --> natT) 
       
   326          $ zero $ zero)
       
   327   end
       
   328 *}
   293 
   329 
   294 section {* Theorems *}
   330 section {* Theorems *}
   295 
   331 
   296 text {*
   332 text {*
   297   Just like @{ML_type cterm}s, theorems (of type @{ML_type thm}) are
   333   Just like @{ML_type cterm}s, theorems (of type @{ML_type thm}) are
   341 end
   377 end
   342 
   378 
   343 *}
   379 *}
   344 
   380 
   345 text {*
   381 text {*
   346   FIXME Explain this program more carefully (@{ML_text assume},  @{ML_text "forall_elim"} \ldots)
   382   For how the functions @{text "assume"}, @{text "forall_elim"} and so on work
   347 *}
   383   see \ichcite{sec:thms}. (FIXME correct name)
   348 
   384 
   349 
   385 
   350 section {* Tactical reasoning *}
   386 *}
       
   387 
       
   388 
       
   389 section {* Tactical Reasoning *}
   351 
   390 
   352 text {*
   391 text {*
   353   The goal-oriented tactical style is similar to the @{text apply}
   392   The goal-oriented tactical style is similar to the @{text apply}
   354   style at the user level. Reasoning is centered around a \emph{goal},
   393   style at the user level. Reasoning is centered around a \emph{goal},
   355   which is modified in a sequence of proof steps until it is solved.
   394   which is modified in a sequence of proof steps until it is solved.
   356 
   395 
   357   A goal (or goal state) is a special @{ML_type thm}, which by
   396   A goal (or goal state) is a special @{ML_type thm}, which by
   358   convention is an implication:
   397   convention is an implication of the form:
       
   398 
   359   @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #(C)"}
   399   @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #(C)"}
   360   Since the final result @{term C} could again be an implication, there is the
   400 
   361   @{text "#"} around the final result, which protects its premises from being
   401   Since the formula @{term C} could potentially be an implication, there is a
       
   402   @{text "#"} wrapped around it, which prevents that premises are 
   362   misinterpreted as open subgoals. The protection @{text "# :: prop \<Rightarrow>
   403   misinterpreted as open subgoals. The protection @{text "# :: prop \<Rightarrow>
   363   prop"} is just the identity and used as a syntactic marker.
   404   prop"} is just the identity function and used as a syntactic marker. 
   364 
   405   For more on this goals see \ichcite{sec:tactical-goals}. (FIXME name)
   365   Now tactics are just functions that map a goal state to a (lazy)
   406 
       
   407   Tactics are functions that map a goal state to a (lazy)
   366   sequence of successor states, hence the type of a tactic is
   408   sequence of successor states, hence the type of a tactic is
   367   @{ML_type[display] "thm -> thm Seq.seq"}
   409   @{ML_type[display] "thm -> thm Seq.seq"}
       
   410   
       
   411   \begin{readmore}
   368   See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy
   412   See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy
   369   sequences.
   413   sequences. However one rarly onstructs sequences manually, but uses
   370 
   414   the predefined tactic combinators (tacticals) instead 
   371   Of course, tactics are expected to behave nicely and leave the final
   415   (see @{ML_file "Pure/tctical.ML"}).
   372   conclusion @{term C} intact. In order to start a tactical proof for
   416   \end{readmore}
   373   @{term A}, we
   417 
   374   just set up the trivial goal @{text "A \<Longrightarrow> #(A)"} and run the tactic
   418   Note, however, that tactics are expected to behave nicely and leave 
   375   on it. When the subgoal is solved, we have just @{text "#(A)"} and
   419   the final conclusion @{term C} intact (that is only work on the @{text "A\<^isub>i"} 
   376   can remove the protection.
   420   representing the subgoals to be proved) with the exception of possibly 
   377 
   421   instantiating schematic variables. 
   378   The operations in @{ML_file "Pure/goal.ML"} do just that and we can use
   422  
   379   them.
   423   To see how tactics work, let us transcribe a simple apply-style proof from the
   380 
   424   tutorial \cite{isa-tutorial} into ML:
   381   Let us transcribe a simple apply style proof from the
       
   382   tutorial\cite{isa-tutorial} into ML:
       
   383 *}
   425 *}
   384 
   426 
   385 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P"
   427 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P"
   386 apply (erule disjE)
   428 apply (erule disjE)
   387  apply (rule disjI2)
   429  apply (rule disjI2)
   388  apply assumption
   430  apply assumption
   389 apply (rule disjI1)
   431 apply (rule disjI1)
   390 apply assumption
   432 apply assumption
   391 done
   433 done
       
   434 
       
   435 
       
   436 text {*
       
   437   
       
   438   To start the proof, the function  @{ML "Goal.prove"}~@{text "ctxt params assms goal tac"}
       
   439   sets up a goal state for proving @{text goal} under the assumptions @{text assms} with
       
   440   additional variables @{text params} (the variables that are generalised once the
       
   441   goal is proved); @{text "tac"} is a function that returns a tactic (FIXME see non-existing
       
   442   explanation in the imp-manual). 
       
   443 
       
   444 *}
       
   445 
       
   446 
   392 
   447 
   393 ML {*
   448 ML {*
   394 let
   449 let
   395   val ctxt = @{context}
   450   val ctxt = @{context}
   396   val goal = @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}
   451   val goal = @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}
   402     THEN resolve_tac [disjI1] 1
   457     THEN resolve_tac [disjI1] 1
   403     THEN assume_tac 1)
   458     THEN assume_tac 1)
   404 end
   459 end
   405 *}
   460 *}
   406 
   461 
   407 text {*
   462 text {* An alternative way to transcribe this proof is as follows *}
   408   Tactics that affect only a certain subgoal, take a subgoal number as
   463 
   409   an integer parameter. Here we always work on the first subgoal,
   464 ML {*
   410   following exactly the @{text "apply"} script.
   465 let
   411 
   466   val ctxt = @{context}
   412   (Fixme: would it make sense to explain THEN' here)
   467   val goal = @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}
   413 
   468 in
   414 *}
   469   Goal.prove ctxt ["P", "Q"] [] goal (fn _ => 
   415 
   470     (eresolve_tac [disjE] 
   416 
   471     THEN' resolve_tac [disjI2] 
   417 section {* Case Study: Relation Composition *}
   472     THEN' assume_tac 
   418 
   473     THEN' resolve_tac [disjI1] 
   419 text {*
   474     THEN' assume_tac) 1)
   420   \emph{Note: This is completely unfinished. I hoped to have a section
       
   421   with a nontrivial example, but I ran into several problems.}
       
   422 
       
   423 
       
   424   Recall that HOL has special syntax for set comprehensions:
       
   425   @{term "{ f x y |x y. P x y}"} abbreviates 
       
   426   @{term[source] "{u. \<exists>x y. u = f x y \<and> P x y}"}. 
       
   427 
       
   428   We will automatically prove statements of the following form:
       
   429   
       
   430   @{lemma[display] "{(l\<^isub>1 x, r\<^isub>1 x) |x. P\<^isub>1 x} O {(l\<^isub>2 x, r\<^isub>2 x) |x. P\<^isub>2 x}
       
   431   = {(l\<^isub>2 x, r\<^isub>1 y) |x y. r\<^isub>2 x = l\<^isub>1 y \<and>
       
   432   P\<^isub>2 x \<and> P\<^isub>1 y}" by auto}
       
   433 
       
   434   In Isabelle, relation composition is defined to be consistent with
       
   435   function composition, that is, the relation applied ``first'' is
       
   436   written on the right hand side. This different from what many
       
   437   textbooks do.
       
   438 
       
   439   The above statement about composition is not proved automatically by
       
   440   @{method simp}, and it cannot be solved by a fixed set of rewrite
       
   441   rules, since the number of (implicit) quantifiers may vary. Here, we
       
   442   only have one bound variable in each comprehension, but in general
       
   443   there can be more. On the other hand, @{method auto} proves the
       
   444   above statement quickly, by breaking the equality into two parts and
       
   445   proving them separately. However, if e.g.\ @{term "P\<^isub>1"} is a
       
   446   complicated expression, the automated tools may get confused.
       
   447 
       
   448   Our goal is now to develop a small procedure that can compute (with proof) the
       
   449   composition of two relation comprehensions, which can be used to
       
   450   extend the simplifier.
       
   451 *}
       
   452 
       
   453 section {*A tactic *}
       
   454 
       
   455 text {* Let's start with a step-by-step proof of the above statement *}
       
   456 
       
   457 lemma "{(l\<^isub>1 x, r\<^isub>1 x) |x. P\<^isub>1 x} O {(l\<^isub>2
       
   458   x, r\<^isub>2 x) |x. P\<^isub>2 x}
       
   459   = {(l\<^isub>2 x, r\<^isub>1 y) |x y. r\<^isub>2 x = l\<^isub>1 y \<and> P\<^isub>2 x \<and> P\<^isub>1 y}"
       
   460 apply (rule set_ext)
       
   461 apply (rule iffI)
       
   462  apply (erule rel_compE)  -- {* @{text "\<subseteq>"} *}
       
   463  apply (erule CollectE)     -- {* eliminate @{text "Collect"}, @{text "\<exists>"}, @{text "\<and>"}, and pairs *}
       
   464  apply (erule CollectE)
       
   465  apply (erule exE)
       
   466  apply (erule exE)
       
   467  apply (erule conjE)
       
   468  apply (erule conjE)
       
   469  apply (erule Pair_inject)
       
   470  apply (erule Pair_inject)
       
   471  apply (simp only:)
       
   472 
       
   473  apply (rule CollectI)    -- {* introduce them again *}
       
   474  apply (rule exI)
       
   475  apply (rule exI)
       
   476  apply (rule conjI)
       
   477   apply (rule refl)
       
   478  apply (rule conjI)
       
   479   apply (rule sym)
       
   480   apply (assumption)
       
   481  apply (rule conjI)
       
   482   apply assumption
       
   483  apply assumption
       
   484 
       
   485 apply (erule CollectE)   -- {* @{text "\<subseteq>"} *}
       
   486 apply (erule exE)+
       
   487 apply (erule conjE)+
       
   488 apply (simp only:)
       
   489 apply (rule rel_compI)
       
   490  apply (rule CollectI)
       
   491  apply (rule exI)
       
   492  apply (rule conjI)
       
   493   apply (rule refl)
       
   494  apply assumption
       
   495 
       
   496 apply (rule CollectI)
       
   497 apply (rule exI)
       
   498 apply (rule conjI)
       
   499 apply (subst Pair_eq)
       
   500 apply (rule conjI)
       
   501  apply assumption
       
   502 apply (rule refl)
       
   503 apply assumption
       
   504 done
       
   505 
       
   506 text {*
       
   507   The reader will probably need to step through the proof and verify
       
   508   that there is nothing spectacular going on here.
       
   509   The @{text apply} script just applies the usual elimination and introduction rules in the right order.
       
   510 
       
   511   This script is of course totally unreadable. But we are not trying
       
   512   to produce pretty Isar proofs here. We just want to find out which
       
   513   rules are needed and how they must be applied to complete the
       
   514   proof. And a detailed apply-style proof can often be turned into a
       
   515   tactic quite easily. Of course we must resist the temptation to use
       
   516   @{method auto}, @{method blast} and friends, since their behaviour
       
   517   is not predictable enough. But the simple @{method rule} and
       
   518   @{method erule} methods are fine.
       
   519 
       
   520   Notice that this proof depends only in one detail on the
       
   521   concrete equation that we want to prove: The number of bound
       
   522   variables in the comprehension corresponds to the number of
       
   523   existential quantifiers that we have to eliminate and introduce
       
   524   again. In fact this is the only reason why the equations that we
       
   525   want to prove are not just instances of a single rule.
       
   526 
       
   527   Here is the ML equivalent of the tactic script above:
       
   528 *}
       
   529 
       
   530 ML {*
       
   531 val compr_compose_tac =
       
   532   rtac @{thm set_ext}
       
   533   THEN' rtac @{thm iffI}
       
   534   THEN' etac @{thm rel_compE}
       
   535   THEN' etac @{thm CollectE}
       
   536   THEN' etac @{thm CollectE}
       
   537   THEN' (fn i => REPEAT (etac @{thm exE} i))
       
   538   THEN' etac @{thm conjE}
       
   539   THEN' etac @{thm conjE}
       
   540   THEN' etac @{thm Pair_inject}
       
   541   THEN' etac @{thm Pair_inject}
       
   542   THEN' asm_full_simp_tac HOL_basic_ss
       
   543   THEN' rtac @{thm CollectI}
       
   544   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   545   THEN' rtac @{thm conjI}
       
   546   THEN' rtac @{thm refl}
       
   547   THEN' rtac @{thm conjI}
       
   548   THEN' rtac @{thm sym}
       
   549   THEN' assume_tac
       
   550   THEN' rtac @{thm conjI}
       
   551   THEN' assume_tac
       
   552   THEN' assume_tac
       
   553 
       
   554   THEN' etac @{thm CollectE}
       
   555   THEN' (fn i => REPEAT (etac @{thm exE} i))
       
   556   THEN' etac @{thm conjE}
       
   557   THEN' etac @{thm conjE}
       
   558   THEN' etac @{thm conjE}
       
   559   THEN' asm_full_simp_tac HOL_basic_ss
       
   560   THEN' rtac @{thm rel_compI}
       
   561   THEN' rtac @{thm CollectI}
       
   562   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   563   THEN' rtac @{thm conjI}
       
   564   THEN' rtac @{thm refl}
       
   565   THEN' assume_tac
       
   566   THEN' rtac @{thm CollectI}
       
   567   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   568   THEN' rtac @{thm conjI}
       
   569   THEN' simp_tac (HOL_basic_ss addsimps [@{thm Pair_eq}])
       
   570   THEN' rtac @{thm conjI}
       
   571   THEN' assume_tac
       
   572   THEN' rtac @{thm refl}
       
   573   THEN' assume_tac
       
   574 *}
       
   575 
       
   576 lemma test1: "{(l\<^isub>1 x, r\<^isub>1 x) |x. P\<^isub>1 x} O {(l\<^isub>2
       
   577   x, r\<^isub>2 x) |x. P\<^isub>2 x}
       
   578   = {(l\<^isub>2 x, r\<^isub>1 y) |x y. r\<^isub>2 x = l\<^isub>1 y \<and> P\<^isub>2 x \<and> P\<^isub>1 y}"
       
   579 by (tactic "compr_compose_tac 1")
       
   580 
       
   581 lemma test3: "{(l\<^isub>1 x, r\<^isub>1 x) |x. P\<^isub>1 x} O {(l\<^isub>2 x z, r\<^isub>2 x z) |x z. P\<^isub>2 x z}
       
   582   = {(l\<^isub>2 x z, r\<^isub>1 y) |x y z. r\<^isub>2 x z = l\<^isub>1 y \<and> P\<^isub>2 x z \<and> P\<^isub>1 y}"
       
   583 by (tactic "compr_compose_tac 1")
       
   584 
       
   585 text {*
       
   586   So we have a tactic that works on at least two examples.
       
   587   Getting it really right requires some more effort. Consider the goal
       
   588 *}
       
   589 lemma "{(n, Suc n) |n. n > 0} O {(n, Suc n) |n. P n}
       
   590   = {(n, Suc m)|n m. Suc n = m \<and> P n \<and> m > 0}"
       
   591 
       
   592 (*lemma "{(l\<^isub>1 x, r\<^isub>1 x) |x. P\<^isub>1 x} O {(l\<^isub>2
       
   593   x, r\<^isub>2 x) |x. P\<^isub>2 x}
       
   594   = {(l\<^isub>2 x, r\<^isub>1 y) |x y. r\<^isub>2 x = l\<^isub>1 y \<and> P\<^isub>2 x \<and> P\<^isub>1 y}"*)
       
   595 txt {*
       
   596   This is exactly an instance of @{fact test1}, but our tactic fails
       
   597   on it with the usual uninformative
       
   598   \emph{empty result requence}.
       
   599 
       
   600   We are now in the frequent situation that we need to debug. One simple instrument for this is @{ML "print_tac"},
       
   601   which is the same as @{ML all_tac} (the identity for @{ML_text "THEN"}),
       
   602   i.e.\ it does nothing, but it prints the current goal state as a
       
   603   side effect.
       
   604   Another debugging option is of course to step through the interactive apply script.
       
   605 
       
   606   Finding the problem could be taken as an exercise for the patient
       
   607   reader, and we will go ahead with the solution.
       
   608 
       
   609   The problem is that in this instance the simplifier does more than it did in the general version
       
   610   of lemma @{fact test1}. Since @{text "l\<^isub>1"} and @{text "l\<^isub>2"} are just the identity function,
       
   611   the equation corresponding to @{text "l\<^isub>1 y = r\<^isub>2 x "}
       
   612   becomes @{text "m = Suc n"}. Then the simplifier eagerly replaces
       
   613   all occurences of @{term "m"} by @{term "Suc n"} which destroys the
       
   614   structure of the proof.
       
   615 
       
   616   This is perhaps the most important lesson to learn, when writing tactics:
       
   617   \textbf{Avoid automation at all cost!!!}.
       
   618 
       
   619   Let us look at the proof state at the point where the simplifier is
       
   620   invoked:
       
   621   
       
   622 *}
       
   623 (*<*)
       
   624 apply (rule set_ext)
       
   625 apply (rule iffI)
       
   626  apply (erule rel_compE)
       
   627  apply (erule CollectE)
       
   628  apply (erule CollectE)
       
   629  apply (erule exE)
       
   630  apply (erule exE)
       
   631  apply (erule conjE)
       
   632  apply (erule conjE)
       
   633  apply (erule Pair_inject)
       
   634  apply (erule Pair_inject)(*>*)
       
   635 txt {*
       
   636   
       
   637   @{subgoals[display]}
       
   638   
       
   639   Like in the apply proof, we now want to eliminate the equations that
       
   640   ``define'' @{term x}, @{term xa} and @{term z}. The other equations
       
   641   are just there by coincidence, and we must not touch them.
       
   642   
       
   643   For such purposes, there is the internal tactic @{text "hyp_subst_single"}.
       
   644   Its job is to take exactly one premise of the form @{term "v = t"},
       
   645   where @{term v} is a variable, and replace @{term "v"} in the whole
       
   646   subgoal. The hypothesis to eliminate is given by its position.
       
   647 
       
   648   We can use this tactic to eliminate @{term x}:
       
   649 *}
       
   650 apply (tactic "single_hyp_subst_tac 0 1")
       
   651 txt {*
       
   652   @{subgoals[display]}
       
   653 *}
       
   654 apply (tactic "single_hyp_subst_tac 2 1")
       
   655 apply (tactic "single_hyp_subst_tac 2 1")
       
   656 apply (tactic "single_hyp_subst_tac 3 1")
       
   657  apply (rule CollectI)    -- {* introduce them again *}
       
   658  apply (rule exI)
       
   659  apply (rule exI)
       
   660  apply (rule conjI)
       
   661   apply (rule refl)
       
   662  apply (rule conjI)
       
   663   apply (assumption)
       
   664  apply (rule conjI)
       
   665   apply assumption
       
   666  apply assumption
       
   667 
       
   668 apply (erule CollectE)   -- {* @{text "\<subseteq>"} *}
       
   669 apply (erule exE)+
       
   670 apply (erule conjE)+
       
   671 apply (tactic "single_hyp_subst_tac 0 1")
       
   672 apply (rule rel_compI)
       
   673  apply (rule CollectI)
       
   674  apply (rule exI)
       
   675  apply (rule conjI)
       
   676   apply (rule refl)
       
   677  apply assumption
       
   678 
       
   679 apply (rule CollectI)
       
   680 apply (rule exI)
       
   681 apply (rule conjI)
       
   682 apply (subst Pair_eq)
       
   683 apply (rule conjI)
       
   684  apply assumption
       
   685 apply (rule refl)
       
   686 apply assumption
       
   687 done
       
   688 
       
   689 ML {*
       
   690 val compr_compose_tac =
       
   691   rtac @{thm set_ext}
       
   692   THEN' rtac @{thm iffI}
       
   693   THEN' etac @{thm rel_compE}
       
   694   THEN' etac @{thm CollectE}
       
   695   THEN' etac @{thm CollectE}
       
   696   THEN' (fn i => REPEAT (etac @{thm exE} i))
       
   697   THEN' etac @{thm conjE}
       
   698   THEN' etac @{thm conjE}
       
   699   THEN' etac @{thm Pair_inject}
       
   700   THEN' etac @{thm Pair_inject}
       
   701   THEN' single_hyp_subst_tac 0
       
   702   THEN' single_hyp_subst_tac 2
       
   703   THEN' single_hyp_subst_tac 2
       
   704   THEN' single_hyp_subst_tac 3
       
   705   THEN' rtac @{thm CollectI}
       
   706   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   707   THEN' rtac @{thm conjI}
       
   708   THEN' rtac @{thm refl}
       
   709   THEN' rtac @{thm conjI}
       
   710   THEN' assume_tac
       
   711   THEN' rtac @{thm conjI}
       
   712   THEN' assume_tac
       
   713   THEN' assume_tac
       
   714 
       
   715   THEN' etac @{thm CollectE}
       
   716   THEN' (fn i => REPEAT (etac @{thm exE} i))
       
   717   THEN' etac @{thm conjE}
       
   718   THEN' etac @{thm conjE}
       
   719   THEN' etac @{thm conjE}
       
   720   THEN' single_hyp_subst_tac 0
       
   721   THEN' rtac @{thm rel_compI}
       
   722   THEN' rtac @{thm CollectI}
       
   723   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   724   THEN' rtac @{thm conjI}
       
   725   THEN' rtac @{thm refl}
       
   726   THEN' assume_tac
       
   727   THEN' rtac @{thm CollectI}
       
   728   THEN' (fn i => REPEAT (rtac @{thm exI} i))
       
   729   THEN' rtac @{thm conjI}
       
   730   THEN' stac @{thm Pair_eq}
       
   731   THEN' rtac @{thm conjI}
       
   732   THEN' assume_tac
       
   733   THEN' rtac @{thm refl}
       
   734   THEN' assume_tac
       
   735 *}
       
   736 
       
   737 lemma "{(n, Suc n) |n. n > 0 \<and> A} O {(n, Suc n) |n m. P m n}
       
   738   = {(n, Suc m)|n m' m. Suc n = m \<and> P m' n \<and> (m > 0 \<and> A)}"
       
   739 apply (tactic "compr_compose_tac 1")
       
   740 done
       
   741 
       
   742 text {*
       
   743   The next step is now to turn this tactic into a simplification
       
   744   procedure. This just means that we need some code that builds the
       
   745   term of the composed relation.
       
   746 *}
       
   747 
       
   748 use "comp_simproc"
       
   749 
       
   750 (*<*)
       
   751 (*simproc_setup mysp ("x O y") = {* compose_simproc *}*)
       
   752 
       
   753 lemma "{(n, Suc n) |n. n > 0 \<and> A} O {(n, Suc n) |n m. P m n} = x"
       
   754 (*apply (simp del:ex_simps)*)
       
   755 oops
       
   756 
       
   757 
       
   758 lemma "({(g m, k) | m k. Q m k} 
       
   759 O {(h j, f j) | j. R j}) = x"
       
   760 (*apply (simp del:ex_simps) *)
       
   761 oops
       
   762 
       
   763 lemma "{uu. \<exists>j m k. uu = (h j, k) \<and> f j = g m \<and> R j \<and> Q m k}
       
   764 O {(h j, f j) | j. R j} = x"
       
   765 (*apply (simp del:ex_simps)*)
       
   766 oops
       
   767 
       
   768 lemma "
       
   769   { (l x, r x) | x. P x \<and> Q x \<and> Q' x }
       
   770 O { (l1 x, r1 x) | x. P1 x \<and> Q1 x \<and> Q1' x }
       
   771 = A"
       
   772 (*apply (simp del:ex_simps)*)
       
   773 oops
       
   774 
       
   775 lemma "
       
   776   { (l x, r x) | x. P x }
       
   777 O { (l1 x, r1 x) | x. P1 x }
       
   778 O { (l2 x, r2 x) | x. P2 x }
       
   779 = A"
       
   780 (*
       
   781 apply (simp del:ex_simps)*)
       
   782 oops
       
   783 
       
   784 lemma "{(f n, m) |n m. P n m} O ({(g m, k) | m k. Q m k} 
       
   785 O {(h j, f j) | j. R j}) = x"
       
   786 (*apply (simp del:ex_simps)*)
       
   787 oops
       
   788 
       
   789 lemma "{u. \<exists>n. u=(f n, g n)} O {u. \<exists>n. u=(h n, j n)} = A"
       
   790 oops
       
   791 
       
   792 
       
   793 (*>*)
       
   794 end
   475 end
       
   476 *}
       
   477 
       
   478 section {* Storing and Changing Theorems and so on *}
       
   479 
       
   480 end