CookBook/FirstSteps.thy
changeset 75 f2dea0465bb4
parent 73 bcbcf5c839ae
child 78 ef778679d3e0
equal deleted inserted replaced
74:f6f8f8ba1eb1 75:f2dea0465bb4
     1 theory FirstSteps
     1 theory FirstSteps
     2 imports Base
     2 imports Base
     3 begin
     3 begin
     4 
       
     5 
     4 
     6 chapter {* First Steps *}
     5 chapter {* First Steps *}
     7 
     6 
     8 text {*
     7 text {*
     9 
     8 
    27 
    26 
    28 text {*
    27 text {*
    29   The easiest and quickest way to include code in a theory is
    28   The easiest and quickest way to include code in a theory is
    30   by using the \isacommand{ML}-command. For example\smallskip
    29   by using the \isacommand{ML}-command. For example\smallskip
    31 
    30 
       
    31 \begin{isabelle}
       
    32 \begin{graybox}
    32 \isa{\isacommand{ML}
    33 \isa{\isacommand{ML}
    33 \isacharverbatimopen\isanewline
    34 \isacharverbatimopen\isanewline
    34 \hspace{5mm}@{ML "3 + 4"}\isanewline
    35 \hspace{5mm}@{ML "3 + 4"}\isanewline
    35 \isacharverbatimclose\isanewline
    36 \isacharverbatimclose\isanewline
    36 @{text "> 7"}\smallskip}
    37 @{text "> 7"}\smallskip}
    37 
    38 \end{graybox}
    38   The @{text [quotes] "> 7"} indicates the response Isabelle prints out when the 
    39 \end{isabelle}
    39   \isacommand{ML}-command is evaluated. Like ``normal'' Isabelle proof scripts, 
    40 
       
    41   Like ``normal'' Isabelle proof scripts, 
    40   \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of 
    42   \isacommand{ML}-commands can be evaluated by using the advance and undo buttons of 
    41   your Isabelle environment. The code inside the \isacommand{ML}-command 
    43   your Isabelle environment. The code inside the \isacommand{ML}-command 
    42   can also contain value and function bindings, and even those can be
    44   can also contain value and function bindings, and even those can be
    43   undone when the proof script is retracted. For better readability, we will in what 
    45   undone when the proof script is retracted. As mentioned earlier, we will  
    44   follows drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} 
    46   drop the \isacommand{ML} \isa{\isacharverbatimopen \ldots \isacharverbatimclose} 
    45   whenever we show code and its response.
    47   whenever we show code and its response.
    46 
    48 
    47   Once a portion of code is relatively stable, one usually wants to 
    49   Once a portion of code is relatively stable, one usually wants to 
    48   export it to a separate ML-file. Such files can then be included in a 
    50   export it to a separate ML-file. Such files can then be included in a 
    49   theory by using \isacommand{uses} in the header of the theory, like
    51   theory by using \isacommand{uses} in the header of the theory, like
    71   @{ML_response_fake [display,gray] "warning \"any string\"" "\"any string\""}
    73   @{ML_response_fake [display,gray] "warning \"any string\"" "\"any string\""}
    72 
    74 
    73   will print out @{text [quotes] "any string"} inside the response buffer
    75   will print out @{text [quotes] "any string"} inside the response buffer
    74   of Isabelle.  This function expects a string as argument. If you develop under PolyML,
    76   of Isabelle.  This function expects a string as argument. If you develop under PolyML,
    75   then there is a convenient, though again ``quick-and-dirty'', method for
    77   then there is a convenient, though again ``quick-and-dirty'', method for
    76   converting values into strings, namely @{ML makestring}:
    78   converting values into strings, namely using the function @{ML makestring}:
    77 
    79 
    78   @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} 
    80   @{ML_response_fake [display,gray] "warning (makestring 1)" "\"1\""} 
    79 
    81 
    80   However @{ML makestring} only works if the type of what is converted is monomorphic 
    82   However @{ML makestring} only works if the type of what is converted is monomorphic 
    81   and is not a function.
    83   and is not a function.
   107      TextIO.flushOut stream)) *}
   109      TextIO.flushOut stream)) *}
   108 
   110 
   109 text {*
   111 text {*
   110   Calling @{ML "redirect_tracing"} with @{ML "(TextIO.openOut \"foo.bar\")"} 
   112   Calling @{ML "redirect_tracing"} with @{ML "(TextIO.openOut \"foo.bar\")"} 
   111   will cause that all tracing information is printed into the file @{text "foo.bar"}.
   113   will cause that all tracing information is printed into the file @{text "foo.bar"}.
   112 *}
   114 
       
   115   Error messages can be printed using the function @{ML error} as in
       
   116 
       
   117   @{ML_response_fake [display,gray] "if 0=1 then 1 else (error \"foo\")" "\"foo\""}
       
   118 
       
   119 *}
       
   120 
       
   121 
   113 
   122 
   114 
   123 
   115 section {* Antiquotations *}
   124 section {* Antiquotations *}
   116 
   125 
   117 text {*
   126 text {*
   143   function is called. Operationally speaking,  the antiquotation @{text "@{theory}"} is 
   152   function is called. Operationally speaking,  the antiquotation @{text "@{theory}"} is 
   144   \emph{not} replaced with code that will look up the current theory in 
   153   \emph{not} replaced with code that will look up the current theory in 
   145   some data structure and return it. Instead, it is literally
   154   some data structure and return it. Instead, it is literally
   146   replaced with the value representing the theory name.
   155   replaced with the value representing the theory name.
   147 
   156 
   148   In a similar way you can use antiquotations to refer to theorems or simpsets:
   157   In a similar way you can use antiquotations to refer to theorems:
   149 
   158 
   150   @{ML_response_fake [display,gray] "@{thm allI}" "(\<And>x. ?P x) \<Longrightarrow> \<forall>x. ?P x"}
   159   @{ML_response_fake [display,gray] "@{thm allI}" "(\<And>x. ?P x) \<Longrightarrow> \<forall>x. ?P x"}
       
   160 
       
   161   or simpsets:
       
   162 
   151   @{ML_response_fake [display,gray] 
   163   @{ML_response_fake [display,gray] 
   152 "let
   164 "let
   153   val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset}
   165   val ({rules,...},_) = MetaSimplifier.rep_ss @{simpset}
   154 in
   166 in
   155   map #name (Net.entries rules)
   167   map #name (Net.entries rules)
   156 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"}
   168 end" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"}
   157 
   169 
   158   The second example extracts the theorem names that are stored in a simpset.
   170   The code above extracts the theorem names that are stored in a simpset.
   159   For this the function @{ML rep_ss in MetaSimplifier} returns a record
   171   We refer to the current simpset with the antiquotation @{text "@{simpset}"}.
   160   containing information about the simpset. The rules of a simpset are stored
   172   The function @{ML rep_ss in MetaSimplifier} returns a record
       
   173   containing all information about the simpset. The rules of a simpset are stored
   161   in a discrimination net (a datastructure for fast indexing). From this net
   174   in a discrimination net (a datastructure for fast indexing). From this net
   162   we can extract the entries using the function @{ML Net.entries}.
   175   we can extract the entries using the function @{ML Net.entries}.
   163 
   176 
   164   While antiquotations have many applications, they were originally introduced to
   177   \begin{readmore}
   165   avoid explicit bindings for theorems such as
   178   The infrastructure for simpsets is implemented in @{ML_file "Pure/meta_simplifier.ML"}
       
   179   and @{ML_file "Pure/simplifier.ML"}.
       
   180   \end{readmore}
       
   181 
       
   182   While antiquotations have many applications, they were originally introduced in order 
       
   183   to avoid explicit bindings for theorems such as
   166 *}
   184 *}
   167 
   185 
   168 ML{*val allI = thm "allI" *}
   186 ML{*val allI = thm "allI" *}
   169 
   187 
   170 text {*
   188 text {*
   171   These bindings were difficult to maintain and also could accidentally
   189   These bindings were difficult to maintain and also could be accidentally
   172   be overwritten by the user. This usually broke definitional
   190   overwritten by the user. This usually broke definitional
   173   packages. Antiquotations solve this problem, since they are ``linked''
   191   packages. Antiquotations solve this problem, since they are ``linked''
   174   statically at compile-time. However, that also sometimes limits their
   192   statically at compile-time. However, this static linkage also limits their
   175   usefulness. In the course of this introduction, we will learn more about
   193   usefulness in cases where data needs to be build up dynamically. In the course of 
       
   194   this introduction, we will learn more about
   176   these antiquotations: they greatly simplify Isabelle programming since one
   195   these antiquotations: they greatly simplify Isabelle programming since one
   177   can directly access all kinds of logical elements from ML.
   196   can directly access all kinds of logical elements from ML.
   178 
   197 
   179 *}
   198 *}
   180 
   199 
   183 text {*
   202 text {*
   184   One way to construct terms of Isabelle on the ML-level is by using the antiquotation 
   203   One way to construct terms of Isabelle on the ML-level is by using the antiquotation 
   185   \mbox{@{text "@{term \<dots>}"}}. For example
   204   \mbox{@{text "@{term \<dots>}"}}. For example
   186 
   205 
   187   @{ML_response [display,gray] 
   206   @{ML_response [display,gray] 
   188     "@{term \"(a::nat) + b = c\"}" 
   207 "@{term \"(a::nat) + b = c\"}" 
   189     "Const (\"op =\", \<dots>) $ (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
   208 "Const (\"op =\", \<dots>) $ 
       
   209                  (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
   190 
   210 
   191   This will show the term @{term "(a::nat) + b = c"}, but printed using the internal
   211   This will show the term @{term "(a::nat) + b = c"}, but printed using the internal
   192   representation of this term. This internal representation corresponds to the 
   212   representation of this term. This internal representation corresponds to the 
   193   datatype @{ML_type "term"}.
   213   datatype @{ML_type "term"}.
   194   
   214   
   220   Hint: The third term is already quite big, and the pretty printer
   240   Hint: The third term is already quite big, and the pretty printer
   221   may omit parts of it by default. If you want to see all of it, you
   241   may omit parts of it by default. If you want to see all of it, you
   222   can use the following ML function to set the limit to a value high 
   242   can use the following ML function to set the limit to a value high 
   223   enough:
   243   enough:
   224 
   244 
   225   @{ML [display] "print_depth 50"}
   245   @{ML [display,gray] "print_depth 50"}
   226   \end{exercise}
   246   \end{exercise}
   227 
   247 
   228   The antiquotation @{text "@{prop \<dots>}"} constructs terms of propositional type, 
   248   The antiquotation @{text "@{prop \<dots>}"} constructs terms of propositional type, 
   229   inserting the invisible @{text "Trueprop"}-coercions whenever necessary. 
   249   inserting the invisible @{text "Trueprop"}-coercions whenever necessary. 
   230   Consider for example the pairs
   250   Consider for example the pairs
   263 *}
   283 *}
   264 
   284 
   265 ML{*fun make_imp P Q tau =
   285 ML{*fun make_imp P Q tau =
   266   let
   286   let
   267     val x = Free ("x",tau)
   287     val x = Free ("x",tau)
   268   in Logic.all x (Logic.mk_implies (P $ x, Q $ x))
   288   in 
       
   289     Logic.all x (Logic.mk_implies (P $ x, Q $ x))
   269   end *}
   290   end *}
   270 
   291 
   271 text {*
   292 text {*
   272 
   293 
   273   The reason is that one cannot pass the arguments @{term P}, @{term Q} and 
   294   The reason is that one cannot pass the arguments @{term P}, @{term Q} and 
   276 
   297 
   277 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *}
   298 ML{*fun make_wrong_imp P Q tau = @{prop "\<And>x. P x \<Longrightarrow> Q x"} *}
   278 
   299 
   279 text {*
   300 text {*
   280   To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} 
   301   To see this apply @{text "@{term S}"}, @{text "@{term T}"} and @{text "@{typ nat}"} 
   281   to both functions. With @{ML make_imp} we obtain the correct term involving 
   302   to both functions. With @{ML make_imp} we obtain the intended term involving 
   282   @{term "S"}, @{text "T"} and  @{text "@{typ nat}"} 
   303   @{term "S"}, @{text "T"} and  @{text "@{typ nat}"} 
   283 
   304 
   284   @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" 
   305   @{ML_response [display,gray] "make_imp @{term S} @{term T} @{typ nat}" 
   285     "Const \<dots> $ 
   306     "Const \<dots> $ 
   286     Abs (\"x\", Type (\"nat\",[]),
   307     Abs (\"x\", Type (\"nat\",[]),
   287       Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ 
   308       Const \<dots> $ (Free (\"S\",\<dots>) $ \<dots>) $ 
   288                   (Free (\"T\",\<dots>) $ \<dots>))"}
   309                   (Free (\"T\",\<dots>) $ \<dots>))"}
   289 
   310 
   290   With @{ML make_wrong_imp} we obtain an incorrect term involving the @{term "P"} 
   311   With @{ML make_wrong_imp} we obtain a term involving the @{term "P"} 
   291   and @{text "Q"} from the antiquotation.
   312   and @{text "Q"} from the antiquotation.
   292 
   313 
   293   @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" 
   314   @{ML_response [display,gray] "make_wrong_imp @{term S} @{term T} @{typ nat}" 
   294     "Const \<dots> $ 
   315     "Const \<dots> $ 
   295     Abs (\"x\", \<dots>,
   316     Abs (\"x\", \<dots>,
   314 
   335 
   315   @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"}
   336   @{ML_response_fake [display,gray] "@{const_name \"Nil\"}" "List.list.Nil"}
   316 
   337 
   317   (FIXME: Is it useful to explain @{text "@{const_syntax}"}?)
   338   (FIXME: Is it useful to explain @{text "@{const_syntax}"}?)
   318 
   339 
   319   Similarly, types can be constructed manually, for example as follows:
   340   Similarly, types can be constructed manually. For example a function type
       
   341   can be constructed as follows:
   320 
   342 
   321 *} 
   343 *} 
   322 
   344 
   323 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *}
   345 ML{*fun make_fun_type tau1 tau2 = Type ("fun",[tau1,tau2]) *}
   324 
   346 
   325 text {*
   347 text {* This can be equally written as *}
   326   which can be equally written as 
       
   327 *}
       
   328 
   348 
   329 ML{*fun make_fun_type tau1 tau2 = tau1 --> tau2 *}
   349 ML{*fun make_fun_type tau1 tau2 = tau1 --> tau2 *}
   330 
   350 
   331 text {*
   351 text {*
   332 
   352 
   349   associates to the left. Try your function on some examples. 
   369   associates to the left. Try your function on some examples. 
   350   \end{exercise}
   370   \end{exercise}
   351 
   371 
   352   \begin{exercise}\label{fun:makesum}
   372   \begin{exercise}\label{fun:makesum}
   353   Write a function which takes two terms representing natural numbers
   373   Write a function which takes two terms representing natural numbers
   354   in unary (like @{term "Suc (Suc (Suc 0))"}), and produce the unary
   374   in unary notation (like @{term "Suc (Suc (Suc 0))"}), and produce the
   355   number representing their sum.
   375   number representing their sum.
   356   \end{exercise}
   376   \end{exercise}
   357 
   377 
   358 *}
   378 *}
   359 
   379 
   391 "let
   411 "let
   392   val natT = @{typ \"nat\"}
   412   val natT = @{typ \"nat\"}
   393   val zero = @{term \"0::nat\"}
   413   val zero = @{term \"0::nat\"}
   394 in
   414 in
   395   cterm_of @{theory} 
   415   cterm_of @{theory} 
   396   (Const (@{const_name plus}, natT --> natT --> natT) 
   416       (Const (@{const_name plus}, natT --> natT --> natT) $ zero $ zero)
   397   $ zero $ zero)
       
   398 end" "0 + 0"}
   417 end" "0 + 0"}
   399 
   418 
   400   \begin{exercise}
   419   \begin{exercise}
   401   Check that the function defined in Exercise~\ref{fun:revsum} returns a
   420   Check that the function defined in Exercise~\ref{fun:revsum} returns a
   402   result that type-checks.
   421   result that type-checks.
   406 
   425 
   407 section {* Theorems *}
   426 section {* Theorems *}
   408 
   427 
   409 text {*
   428 text {*
   410   Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} 
   429   Just like @{ML_type cterm}s, theorems are abstract objects of type @{ML_type thm} 
   411   that can only be built by going through interfaces. In effect all proofs 
   430   that can only be built by going through interfaces. As a consequence of this is that
   412   are checked. 
   431   every proof is correct by construction (FIXME reference LCF-philosophy)
   413 
   432 
   414   To see theorems in ``action'', let us give a proof for the following statement
   433   To see theorems in ``action'', let us give a proof for the following statement
   415 *}
   434 *}
   416 
   435 
   417   lemma 
   436   lemma 
   419    and     assm\<^isub>2: "P t"
   438    and     assm\<^isub>2: "P t"
   420    shows "Q t" (*<*)oops(*>*) 
   439    shows "Q t" (*<*)oops(*>*) 
   421 
   440 
   422 text {*
   441 text {*
   423   on the ML-level:\footnote{Note that @{text "|>"} is reverse
   442   on the ML-level:\footnote{Note that @{text "|>"} is reverse
   424   application. This combinator, and several variants are defined in
   443   application. See Section~\ref{sec:combinators}.}
   425   @{ML_file "Pure/General/basics.ML"}.}
       
   426 
   444 
   427 @{ML_response_fake [display,gray]
   445 @{ML_response_fake [display,gray]
   428 "let
   446 "let
   429   val thy = @{theory}
   447   val thy = @{theory}
   430 
   448 
   465   @{ML_file "Pure/thm.ML"}. 
   483   @{ML_file "Pure/thm.ML"}. 
   466   \end{readmore}
   484   \end{readmore}
   467 
   485 
   468 *}
   486 *}
   469 
   487 
   470 
   488 section {* Storing Theorems *}
   471 section {* Tactical Reasoning *}
   489 
   472 
   490 section {* Theorem Attributes *}
   473 text {*
   491 
   474   The goal-oriented tactical style reasoning of the ML level is similar 
   492 section {* Operations on Constants (Names) *}
   475   to the @{text apply}-style at the user level, i.e.~the reasoning is centred 
   493 
   476   around a \emph{goal}, which is modified in a sequence of proof steps 
   494 text {*
   477   until it is solved.
   495   (FIXME how can I extract the constant name without the theory name etc)
   478 
   496 *}
   479   A goal (or goal state) is a special @{ML_type thm}, which by
   497 
   480   convention is an implication of the form:
   498 section {* Combinators\label{sec:combinators} *}
   481 
   499 
   482   @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #(C)"}
   500 text {*
   483 
   501   Perhaps one of the most puzzling aspects for a beginner when reading at 
   484   where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the open 
   502   existing Isabelle code is the liberal use of combinators. At first they 
   485   subgoals. 
   503   seem to obstruct the comprehension of the code, but after getting familiar 
   486   Since the goal @{term C} can potentially be an implication, there is a
   504   with them they actually ease the reading and also the programming.
   487   @{text "#"} wrapped around it, which prevents that premises are 
   505 
   488   misinterpreted as open subgoals. The wrapper @{text "# :: prop \<Rightarrow>
       
   489   prop"} is just the identity function and used as a syntactic marker. 
       
   490   
       
   491   \begin{readmore}
   506   \begin{readmore}
   492   For more on goals see \isccite{sec:tactical-goals}. (FIXME: in which
   507   The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"}
   493   file is most code for dealing with goals?)
       
   494   \end{readmore}
       
   495 
       
   496   Tactics are functions that map a goal state to a (lazy)
       
   497   sequence of successor states, hence the type of a tactic is
       
   498   
       
   499   @{ML_type[display] "thm -> thm Seq.seq"}
       
   500   
       
   501   \begin{readmore}
       
   502   See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy
       
   503   sequences. However in day-to-day Isabelle programming, one rarely 
       
   504   constructs sequences explicitly, but uses the predefined tactic 
       
   505   combinators (tacticals) instead. See @{ML_file "Pure/tctical.ML"} 
       
   506   for the code; see Chapters 3 and 4 in the old Isabelle Reference Manual.
       
   507   \end{readmore}
       
   508 
       
   509   While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they 
       
   510   are expected to leave the conclusion @{term C} intact, with the 
       
   511   exception of possibly instantiating schematic variables. 
       
   512  
       
   513   To see how tactics work, let us transcribe a simple @{text apply}-style 
       
   514   proof into ML:
       
   515 *}
       
   516 
       
   517 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P"
       
   518 apply (erule disjE)
       
   519  apply (rule disjI2)
       
   520  apply assumption
       
   521 apply (rule disjI1)
       
   522 apply assumption
       
   523 done
       
   524 
       
   525 text {*
       
   526   To start the proof, the function  @{ML "Goal.prove"}~@{text "ctxt xs As C tac"} sets 
       
   527   up a goal state for proving the goal @{text C} under the assumptions @{text As} 
       
   528   (empty in the proof at hand) 
       
   529   with the variables @{text xs} that will be generalised once the
       
   530   goal is proved. The @{text "tac"} is the tactic which proves the goal and which 
       
   531   can make use of the local assumptions (there are none in this example).
       
   532 
       
   533 @{ML_response_fake [display,gray]
       
   534 "let
       
   535   val ctxt = @{context}
       
   536   val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"}
       
   537 in
       
   538   Goal.prove ctxt [\"P\", \"Q\"] [] goal (fn _ => 
       
   539     eresolve_tac [disjE] 1
       
   540     THEN resolve_tac [disjI2] 1
       
   541     THEN assume_tac 1
       
   542     THEN resolve_tac [disjI1] 1
       
   543     THEN assume_tac 1)
       
   544 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"}
       
   545 
       
   546   \begin{readmore}
       
   547   To learn more about the function @{ML Goal.prove} see \isccite{sec:results} and
       
   548   the file @{ML_file "Pure/goal.ML"}.
       
   549   \end{readmore}
       
   550 
       
   551 
       
   552   An alternative way to transcribe this proof is as follows 
       
   553 
       
   554 @{ML_response_fake [display,gray]
       
   555 "let
       
   556   val ctxt = @{context}
       
   557   val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"}
       
   558 in
       
   559   Goal.prove ctxt [\"P\", \"Q\"] [] goal (fn _ => 
       
   560     (eresolve_tac [disjE] 
       
   561     THEN' resolve_tac [disjI2] 
       
   562     THEN' assume_tac 
       
   563     THEN' resolve_tac [disjI1] 
       
   564     THEN' assume_tac) 1)
       
   565 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"}
       
   566 
       
   567   (FIXME: are there any advantages/disadvantages about this way?) 
       
   568 *}
       
   569 
       
   570 section {* Storing Theorems *}
       
   571 
       
   572 section {* Theorem Attributes *}
       
   573 
       
   574 
       
   575 section {* Combinators *}
       
   576 
       
   577 text {*
       
   578   Perhaps one of the most puzzling aspects for a beginner when looking at 
       
   579   existing Isabelle code is the liberal use of combinators. At first they 
       
   580   seem to obstruct reading the code, but after getting familiar with them 
       
   581   they actually ease the reading and also the programming.
       
   582 
       
   583   \begin{readmore}
       
   584   The most frequently used combinator are defined in @{ML_file "Pure/library.ML"}
       
   585   and @{ML_file "Pure/General/basics.ML"}.
   508   and @{ML_file "Pure/General/basics.ML"}.
   586   \end{readmore}
   509   \end{readmore}
   587 
   510 
   588   The simplest combinator is @{ML I} which is just the identidy function.
   511   The simplest combinator is @{ML I} which is just the identidy function.
   589 *}
   512 *}
   590 
   513 
   591 ML{*fun I x = x*}
   514 ML{*fun I x = x*}
   592 
   515 
   593 text {*
   516 text {* Another frequently used combinator is @{ML K} *}
   594   Another frequently used combinator is @{ML K}
   517 
   595 
   518 ML{*fun K x = fn _ => x*}
   596   
   519 
   597 *}
   520 text {*
       
   521   which ``wraps'' a function around the argument @{text "x"}. This function 
       
   522   ignores its argument. 
       
   523 
       
   524   @{ML "(op |>)"}
       
   525 *}
       
   526 
       
   527 ML{*fun x |> f = f x*}
   598 
   528 
   599 end
   529 end