CookBook/FirstSteps.thy
changeset 126 fcc0e6e54dca
parent 124 0b9fa606a746
child 127 74846cb0fff9
equal deleted inserted replaced
125:748d9c1a32fb 126:fcc0e6e54dca
    60   \end{tabular}
    60   \end{tabular}
    61   \end{center}
    61   \end{center}
    62   
    62   
    63 *}
    63 *}
    64 
    64 
    65 section {* Debugging and Printing *}
    65 section {* Debugging and Printing\label{sec:printing} *}
    66 
    66 
    67 text {*
    67 text {*
    68 
    68 
    69   During development you might find it necessary to inspect some data
    69   During development you might find it necessary to inspect some data
    70   in your code. This can be done in a ``quick-and-dirty'' fashion using 
    70   in your code. This can be done in a ``quick-and-dirty'' fashion using 
   116 
   116 
   117 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" 
   117 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" 
   118 "Exception- ERROR \"foo\" raised
   118 "Exception- ERROR \"foo\" raised
   119 At command \"ML\"."}
   119 At command \"ML\"."}
   120 
   120 
   121   Section~\ref{sec:printing} will give more information about printing 
   121   Most often you want to inspect data of type @{ML_type term}, @{ML_type cterm} 
   122   the main data structures of Isabelle, namely @{ML_type term}, @{ML_type cterm} 
   122   or @{ML_type thm}. Isabelle contains elaborate pretty-printing functions for printing them, 
   123   and @{ML_type thm}.
   123   but  for quick-and-dirty solutions they are far too unwieldy. A simple way to transform 
       
   124   a term into a string is to use the function @{ML Syntax.string_of_term}.
       
   125 
       
   126   @{ML_response_fake [display,gray]
       
   127   "Syntax.string_of_term @{context} @{term \"1::nat\"}"
       
   128   "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""}
       
   129 
       
   130   This produces a string with some additional information encoded in it. The string
       
   131   can be properly printed by using the function @{ML warning}.
       
   132 
       
   133   @{ML_response_fake [display,gray]
       
   134   "warning (Syntax.string_of_term @{context} @{term \"1::nat\"})"
       
   135   "\"1\""}
       
   136 
       
   137   A @{ML_type cterm} can be transformed into a string by the following function.
       
   138 *}
       
   139 
       
   140 ML{*fun str_of_cterm ctxt t =  
       
   141    Syntax.string_of_term ctxt (term_of t)*}
       
   142 
       
   143 text {*
       
   144   If there are more than one @{ML_type cterm}s to be printed, you can use the 
       
   145   function @{ML commas} to separate them.
       
   146 *} 
       
   147 
       
   148 ML{*fun str_of_cterms ctxt ts =  
       
   149    commas (map (str_of_cterm ctxt) ts)*}
       
   150 
       
   151 text {*
       
   152   The easiest way to get the string of a theorem is to transform it
       
   153   into a @{ML_type cterm} using the function @{ML crep_thm}.
       
   154 *}
       
   155 
       
   156 ML{*fun str_of_thm ctxt thm =
       
   157   let
       
   158     val {prop, ...} = crep_thm thm
       
   159   in 
       
   160     str_of_cterm ctxt prop
       
   161   end*}
       
   162 
       
   163 text {* 
       
   164   Again the function @{ML commas} helps with printing more than one theorem. 
       
   165 *}
       
   166 
       
   167 ML{*fun str_of_thms ctxt thms =  
       
   168   commas (map (str_of_thm ctxt) thms)*}
       
   169 
       
   170 
       
   171 section {* Combinators\label{sec:combinators} *}
       
   172 
       
   173 text {*
       
   174   (FIXME: maybe move before antiquotation section)
       
   175 
       
   176   For beginners, perhaps the most puzzling parts in the existing code of Isabelle are
       
   177   the combinators. At first they seem to greatly obstruct the
       
   178   comprehension of the code, but after getting familiar with them, they
       
   179   actually ease the understanding and also the programming.
       
   180 
       
   181   \begin{readmore}
       
   182   The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"}
       
   183   and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} 
       
   184   contains further information about combinators.
       
   185   \end{readmore}
       
   186 
       
   187   The simplest combinator is @{ML I}, which is just the identity function defined as
       
   188 *}
       
   189 
       
   190 ML{*fun I x = x*}
       
   191 
       
   192 text {* Another simple combinator is @{ML K}, defined as *}
       
   193 
       
   194 ML{*fun K x = fn _ => x*}
       
   195 
       
   196 text {*
       
   197   @{ML K} ``wraps'' a function around the argument @{text "x"}. However, this 
       
   198   function ignores its argument. As a result, @{ML K} defines a constant function 
       
   199   always returning @{text x}.
       
   200 
       
   201   The next combinator is reverse application, @{ML "|>"}, defined as: 
       
   202 *}
       
   203 
       
   204 ML{*fun x |> f = f x*}
       
   205 
       
   206 text {* While just syntactic sugar for the usual function application,
       
   207   the purpose of this combinator is to implement functions in a  
       
   208   ``waterfall fashion''. Consider for example the function *}
       
   209 
       
   210 ML %linenosgray{*fun inc_by_five x =
       
   211   x |> (fn x => x + 1)
       
   212     |> (fn x => (x, x))
       
   213     |> fst
       
   214     |> (fn x => x + 4)*}
       
   215 
       
   216 text {*
       
   217   which increments its argument @{text x} by 5. It does this by first incrementing 
       
   218   the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking 
       
   219   the first component of the pair (Line 4) and finally incrementing the first 
       
   220   component by 4 (Line 5). This kind of cascading manipulations of values is quite
       
   221   common when dealing with theories (for example by adding a definition, followed by
       
   222   lemmas and so on). The reverse application allows you to read what happens in 
       
   223   a top-down manner. This kind of coding should also be familiar, 
       
   224   if you used Haskell's do-notation. Writing the function @{ML inc_by_five} using 
       
   225   the reverse application is much clearer than writing
       
   226 *}
       
   227 
       
   228 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*}
       
   229 
       
   230 text {* or *}
       
   231 
       
   232 ML{*fun inc_by_five x = 
       
   233        ((fn x => x + 4) o fst o (fn x => (x, x)) o (fn x => x + 1)) x*}
       
   234 
       
   235 text {* and typographically more economical than *}
       
   236 
       
   237 ML{*fun inc_by_five x =
       
   238    let val y1 = x + 1
       
   239        val y2 = (y1, y1)
       
   240        val y3 = fst y2
       
   241        val y4 = y3 + 4
       
   242    in y4 end*}
       
   243 
       
   244 text {* 
       
   245   Another reason why the let-bindings in the code above are better to be
       
   246   avoided: it is more than easy to get the intermediate values wrong, not to 
       
   247   mention the nightmares the maintenance of this code causes!
       
   248 
       
   249 
       
   250   (FIXME: give a real world example involving theories)
       
   251 
       
   252   Similarly, the combinator @{ML "#>"} is the reverse function 
       
   253   composition. It can be used to define the following function
       
   254 *}
       
   255 
       
   256 ML{*val inc_by_six = 
       
   257       (fn x => x + 1)
       
   258    #> (fn x => x + 2)
       
   259    #> (fn x => x + 3)*}
       
   260 
       
   261 text {* 
       
   262   which is the function composed of first the increment-by-one function and then
       
   263   increment-by-two, followed by increment-by-three. Again, the reverse function 
       
   264   composition allows you to read the code top-down.
       
   265 
       
   266   The remaining combinators described in this section add convenience for the
       
   267   ``waterfall method'' of writing functions. The combinator @{ML tap} allows
       
   268   you to get hold of an intermediate result (to do some side-calculations for
       
   269   instance). The function
       
   270 
       
   271  *}
       
   272 
       
   273 ML %linenosgray{*fun inc_by_three x =
       
   274      x |> (fn x => x + 1)
       
   275        |> tap (fn x => tracing (makestring x))
       
   276        |> (fn x => x + 2)*}
       
   277 
       
   278 text {* 
       
   279   increments the argument first by @{text "1"} and then by @{text "2"}. In the
       
   280   middle (Line 3), however, it uses @{ML tap} for printing the ``plus-one''
       
   281   intermediate result inside the tracing buffer. The function @{ML tap} can
       
   282   only be used for side-calculations, because any value that is computed
       
   283   cannot be merged back into the ``main waterfall''. To do this, you can use
       
   284   the next combinator.
       
   285 
       
   286   The combinator @{ML "`"} is similar to @{ML tap}, but applies a function to the value
       
   287   and returns the result together with the value (as a pair). For example
       
   288   the function 
       
   289 *}
       
   290 
       
   291 ML{*fun inc_as_pair x =
       
   292      x |> `(fn x => x + 1)
       
   293        |> (fn (x, y) => (x, y + 1))*}
       
   294 
       
   295 text {*
       
   296   takes @{text x} as argument, and then increments @{text x}, but also keeps
       
   297   @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)"
       
   298   for x}. After that, the function increments the right-hand component of the
       
   299   pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}.
       
   300 
       
   301   The combinators @{ML "|>>"} and @{ML "||>"} are defined for 
       
   302   functions manipulating pairs. The first applies the function to
       
   303   the first component of the pair, defined as
       
   304 *}
       
   305 
       
   306 ML{*fun (x, y) |>> f = (f x, y)*}
       
   307 
       
   308 text {*
       
   309   and the second combinator to the second component, defined as
       
   310 *}
       
   311 
       
   312 ML{*fun (x, y) ||> f = (x, f y)*}
       
   313 
       
   314 text {*
       
   315   With the combinator @{ML "|->"} you can re-combine the elements from a pair.
       
   316   This combinator is defined as
       
   317 *}
       
   318 
       
   319 ML{*fun (x, y) |-> f = f x y*}
       
   320 
       
   321 text {* and can be used to write the following roundabout version 
       
   322   of the @{text double} function: 
       
   323 *}
       
   324 
       
   325 ML{*fun double x =
       
   326       x |>  (fn x => (x, x))
       
   327         |-> (fn x => fn y => x + y)*}
       
   328 
       
   329 text {*
       
   330   Recall that @{ML "|>"} is the reverse function applications. Recall also that the related 
       
   331   reverse function composition is @{ML "#>"}. In fact all the combinators @{ML "|->"},
       
   332   @{ML "|>>"} and @{ML "||>"} described above have related combinators for function
       
   333   composition, namely @{ML "#->"}, @{ML "#>>"} and @{ML "##>"}. Using @{ML "#->"}, 
       
   334   for example, the function @{text double} can also be written as:
       
   335 *}
       
   336 
       
   337 ML{*val double =
       
   338             (fn x => (x, x))
       
   339         #-> (fn x => fn y => x + y)*}
       
   340 
       
   341 text {*
       
   342   
       
   343   (FIXME: find a good exercise for combinators)
       
   344  
   124 *}
   345 *}
   125 
   346 
   126 
   347 
   127 section {* Antiquotations *}
   348 section {* Antiquotations *}
   128 
   349 
   210   \mbox{@{text "@{term \<dots>}"}}. For example:
   431   \mbox{@{text "@{term \<dots>}"}}. For example:
   211 
   432 
   212   @{ML_response [display,gray] 
   433   @{ML_response [display,gray] 
   213 "@{term \"(a::nat) + b = c\"}" 
   434 "@{term \"(a::nat) + b = c\"}" 
   214 "Const (\"op =\", \<dots>) $ 
   435 "Const (\"op =\", \<dots>) $ 
   215                  (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
   436    (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"}
   216 
   437 
   217   This will show the term @{term "(a::nat) + b = c"}, but printed using the internal
   438   This will show the term @{term "(a::nat) + b = c"}, but printed using the internal
   218   representation of this term. This internal representation corresponds to the 
   439   representation of this term. This internal representation corresponds to the 
   219   datatype @{ML_type "term"}.
   440   datatype @{ML_type "term"}.
   220   
   441   
   254 
   475 
   255   The antiquotation @{text "@{prop \<dots>}"} constructs terms of propositional type, 
   476   The antiquotation @{text "@{prop \<dots>}"} constructs terms of propositional type, 
   256   inserting the invisible @{text "Trueprop"}-coercions whenever necessary. 
   477   inserting the invisible @{text "Trueprop"}-coercions whenever necessary. 
   257   Consider for example the pairs
   478   Consider for example the pairs
   258 
   479 
   259   @{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" "(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>),
   480 @{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" 
   260  Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"}
   481 "(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>),
       
   482   Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"}
   261  
   483  
   262   where a coercion is inserted in the second component and 
   484   where a coercion is inserted in the second component and 
   263 
   485 
   264   @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" 
   486   @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" 
   265   "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"}
   487   "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"}
   443   (@{text "list"}). Even worse, some constants have a name involving 
   665   (@{text "list"}). Even worse, some constants have a name involving 
   444   type-classes. Consider for example the constants for @{term "zero"} 
   666   type-classes. Consider for example the constants for @{term "zero"} 
   445   and @{text "(op *)"}:
   667   and @{text "(op *)"}:
   446 
   668 
   447   @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"op *\"})" 
   669   @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"op *\"})" 
   448   "(Const (\"HOL.zero_class.zero\", \<dots>), 
   670  "(Const (\"HOL.zero_class.zero\", \<dots>), 
   449  Const (\"HOL.times_class.times\", \<dots>))"}
   671  Const (\"HOL.times_class.times\", \<dots>))"}
   450 
   672 
   451   While you could use the complete name, for example 
   673   While you could use the complete name, for example 
   452   @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or
   674   @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or
   453   matching against @{text "Nil"}, this would make the code rather brittle. 
   675   matching against @{text "Nil"}, this would make the code rather brittle. 
   469   @{ML Sign.base_name}. For example:
   691   @{ML Sign.base_name}. For example:
   470 
   692 
   471   @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""}
   693   @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""}
   472 
   694 
   473   The difference between both functions is that @{ML extern_const in Sign} returns
   695   The difference between both functions is that @{ML extern_const in Sign} returns
   474   the smallest name which is still unique, while @{ML base_name in Sign} always
   696   the smallest name that is still unique, whereas @{ML base_name in Sign} always
   475   strips off all qualifiers.
   697   strips off all qualifiers.
   476 
   698 
   477   (FIXME authentic syntax on the ML-level)
   699   (FIXME authentic syntax on the ML-level)
   478 
   700 
   479   \begin{readmore}
   701   \begin{readmore}
   565   type @{ML "dummyT"} and then let type-inference figure out the 
   787   type @{ML "dummyT"} and then let type-inference figure out the 
   566   complete type. An example is as follows:
   788   complete type. An example is as follows:
   567 
   789 
   568   @{ML_response_fake [display,gray] 
   790   @{ML_response_fake [display,gray] 
   569 "let
   791 "let
   570   val term = 
   792   val c = Const (@{const_name \"plus\"}, dummyT) 
   571    Const (@{const_name \"plus\"}, dummyT) $ @{term \"1::nat\"} $ Free (\"x\", dummyT)
   793   val o = @{term \"1::nat\"} 
       
   794   val v = Free (\"x\", dummyT)
   572 in   
   795 in   
   573   Syntax.check_term @{context} term
   796   Syntax.check_term @{context} (c $ o $ v)
   574 end"
   797 end"
   575   "Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $
   798 "Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $
   576        Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"}
   799   Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"}
   577 
   800 
   578   Instead of giving explicitly the type for the constant @{text "plus"} and the free 
   801   Instead of giving explicitly the type for the constant @{text "plus"} and the free 
   579   variable @{text "x"}, the type-inference will fill in the missing information.
   802   variable @{text "x"}, the type-inference will fill in the missing information.
   580 
   803 
   581 
   804 
   652   \end{readmore}
   875   \end{readmore}
   653 
   876 
   654   (FIXME: how to add case-names to goal states)
   877   (FIXME: how to add case-names to goal states)
   655 *}
   878 *}
   656 
   879 
   657 section {* Printing Terms and Theorems\label{sec:printing} *}
       
   658 
       
   659 text {* 
       
   660   During development, you often want to inspect date of type @{ML_type term}, @{ML_type cterm} 
       
   661   or @{ML_type thm}. Isabelle contains elaborate pretty-printing functions for printing them, 
       
   662   but  for quick-and-dirty solutions they are far too unwieldy. A simple way to transform 
       
   663   a term into a string is to use the function @{ML Syntax.string_of_term}.
       
   664 
       
   665   @{ML_response_fake [display,gray]
       
   666   "Syntax.string_of_term @{context} @{term \"1::nat\"}"
       
   667   "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""}
       
   668 
       
   669   This produces a string with some printing directions encoded in it. The string
       
   670   can be properly printed by using the function @{ML warning}.
       
   671 
       
   672   @{ML_response_fake [display,gray]
       
   673   "warning (Syntax.string_of_term @{context} @{term \"1::nat\"})"
       
   674   "\"1\""}
       
   675 
       
   676   A @{ML_type cterm} can be transformed into a string by the following function.
       
   677 *}
       
   678 
       
   679 ML{*fun str_of_cterm ctxt t =  
       
   680    Syntax.string_of_term ctxt (term_of t)*}
       
   681 
       
   682 text {*
       
   683   If there are more than one @{ML_type cterm}s to be printed, you can use the 
       
   684   function @{ML commas} to separate them.
       
   685 *} 
       
   686 
       
   687 ML{*fun str_of_cterms ctxt ts =  
       
   688    commas (map (str_of_cterm ctxt) ts)*}
       
   689 
       
   690 text {*
       
   691   The easiest way to get the string of a theorem is to transform it
       
   692   into a @{ML_type cterm} using the function @{ML crep_thm}.
       
   693 *}
       
   694 
       
   695 ML{*fun str_of_thm ctxt thm =
       
   696   let
       
   697     val {prop, ...} = crep_thm thm
       
   698   in 
       
   699     str_of_cterm ctxt prop
       
   700   end*}
       
   701 
       
   702 text {* 
       
   703   Again the function @{ML commas} helps with printing more than one theorem. 
       
   704 *}
       
   705 
       
   706 ML{*fun str_of_thms ctxt thms =  
       
   707   commas (map (str_of_thm ctxt) thms)*}
       
   708 
   880 
   709 section {* Theorem Attributes *}
   881 section {* Theorem Attributes *}
   710 
   882 
   711 section {* Theories and Local Theories *}
   883 section {* Theories and Local Theories *}
   712 
   884 
       
   885 text {*
       
   886   (FIXME: expand)
       
   887 
       
   888   There are theories, proof contexts and local theories (in this order, if you
       
   889   want to order them). 
       
   890 
       
   891   In contrast to an ordinary theory, which simply consists of a type
       
   892   signature, as well as tables for constants, axioms and theorems, a local
       
   893   theory also contains additional context information, such as locally fixed
       
   894   variables and local assumptions that may be used by the package. The type
       
   895   @{ML_type local_theory} is identical to the type of \emph{proof contexts}
       
   896   @{ML_type "Proof.context"}, although not every proof context constitutes a
       
   897   valid local theory.
       
   898 
       
   899  *}
       
   900 
       
   901 
       
   902 
   713 section {* Storing Theorems *}
   903 section {* Storing Theorems *}
   714 
   904 
   715 text {* @{ML PureThy.add_thms_dynamic} *}
   905 text {* @{ML PureThy.add_thms_dynamic} *}
   716 
   906 
   717 
   907 
   718 section {* Combinators\label{sec:combinators} *}
   908 
   719 
   909 (* FIXME: some code below *)
   720 text {*
       
   721   For beginners, perhaps the most puzzling parts in the existing code of Isabelle are
       
   722   the combinators. At first they seem to greatly obstruct the
       
   723   comprehension of the code, but after getting familiar with them, they
       
   724   actually ease the understanding and also the programming.
       
   725 
       
   726   \begin{readmore}
       
   727   The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"}
       
   728   and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} 
       
   729   contains further information about combinators.
       
   730   \end{readmore}
       
   731 
       
   732   The simplest combinator is @{ML I}, which is just the identity function defined as
       
   733 *}
       
   734 
       
   735 ML{*fun I x = x*}
       
   736 
       
   737 text {* Another simple combinator is @{ML K}, defined as *}
       
   738 
       
   739 ML{*fun K x = fn _ => x*}
       
   740 
       
   741 text {*
       
   742   @{ML K} ``wraps'' a function around the argument @{text "x"}. However, this 
       
   743   function ignores its argument. As a result, @{ML K} defines a constant function 
       
   744   always returning @{text x}.
       
   745 
       
   746   The next combinator is reverse application, @{ML "|>"}, defined as: 
       
   747 *}
       
   748 
       
   749 ML{*fun x |> f = f x*}
       
   750 
       
   751 text {* While just syntactic sugar for the usual function application,
       
   752   the purpose of this combinator is to implement functions in a  
       
   753   ``waterfall fashion''. Consider for example the function *}
       
   754 
       
   755 ML %linenosgray{*fun inc_by_five x =
       
   756   x |> (fn x => x + 1)
       
   757     |> (fn x => (x, x))
       
   758     |> fst
       
   759     |> (fn x => x + 4)*}
       
   760 
       
   761 text {*
       
   762   which increments its argument @{text x} by 5. It does this by first incrementing 
       
   763   the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking 
       
   764   the first component of the pair (Line 4) and finally incrementing the first 
       
   765   component by 4 (Line 5). This kind of cascading manipulations of values is quite
       
   766   common when dealing with theories (for example by adding a definition, followed by
       
   767   lemmas and so on). The reverse application allows you to read what happens in 
       
   768   a top-down manner. This kind of coding should also be familiar, 
       
   769   if you used Haskell's do-notation. Writing the function @{ML inc_by_five} using 
       
   770   the reverse application is much clearer than writing
       
   771 *}
       
   772 
       
   773 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*}
       
   774 
       
   775 text {* or *}
       
   776 
       
   777 ML{*fun inc_by_five x = 
       
   778        ((fn x => x + 4) o fst o (fn x => (x, x)) o (fn x => x + 1)) x*}
       
   779 
       
   780 text {* and typographically more economical than *}
       
   781 
       
   782 ML{*fun inc_by_five x =
       
   783    let val y1 = x + 1
       
   784        val y2 = (y1, y1)
       
   785        val y3 = fst y2
       
   786        val y4 = y3 + 4
       
   787    in y4 end*}
       
   788 
       
   789 text {* 
       
   790   Another reason why the let-bindings in the code above are better to be
       
   791   avoided: it is more than easy to get the intermediate values wrong, not to 
       
   792   mention the nightmares the maintenance of this code causes!
       
   793 
       
   794 
       
   795   (FIXME: give a real world example involving theories)
       
   796 
       
   797   Similarly, the combinator @{ML "#>"} is the reverse function 
       
   798   composition. It can be used to define the following function
       
   799 *}
       
   800 
       
   801 ML{*val inc_by_six = 
       
   802       (fn x => x + 1)
       
   803    #> (fn x => x + 2)
       
   804    #> (fn x => x + 3)*}
       
   805 
       
   806 text {* 
       
   807   which is the function composed of first the increment-by-one function and then
       
   808   increment-by-two, followed by increment-by-three. Again, the reverse function 
       
   809   composition allows you to read the code top-down.
       
   810 
       
   811   The remaining combinators described in this section add convenience for the
       
   812   ``waterfall method'' of writing functions. The combinator @{ML tap} allows
       
   813   you to get hold of an intermediate result (to do some side-calculations for
       
   814   instance). The function
       
   815 
       
   816  *}
       
   817 
       
   818 ML %linenosgray{*fun inc_by_three x =
       
   819      x |> (fn x => x + 1)
       
   820        |> tap (fn x => tracing (makestring x))
       
   821        |> (fn x => x + 2)*}
       
   822 
       
   823 text {* 
       
   824   increments the argument first by @{text "1"} and then by @{text "2"}. In the
       
   825   middle (Line 3), however, it uses @{ML tap} for printing the ``plus-one''
       
   826   intermediate result inside the tracing buffer. The function @{ML tap} can
       
   827   only be used for side-calculations, because any value that is computed
       
   828   cannot be merged back into the ``main waterfall''. To do this, you can use
       
   829   the next combinator.
       
   830 
       
   831   The combinator @{ML "`"} is similar to @{ML tap}, but applies a function to the value
       
   832   and returns the result together with the value (as a pair). For example
       
   833   the function 
       
   834 *}
       
   835 
       
   836 ML{*fun inc_as_pair x =
       
   837      x |> `(fn x => x + 1)
       
   838        |> (fn (x, y) => (x, y + 1))*}
       
   839 
       
   840 text {*
       
   841   takes @{text x} as argument, and then increments @{text x}, but also keeps
       
   842   @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)"
       
   843   for x}. After that, the function increments the right-hand component of the
       
   844   pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}.
       
   845 
       
   846   The combinators @{ML "|>>"} and @{ML "||>"} are defined for 
       
   847   functions manipulating pairs. The first applies the function to
       
   848   the first component of the pair, defined as
       
   849 *}
       
   850 
       
   851 ML{*fun (x, y) |>> f = (f x, y)*}
       
   852 
       
   853 text {*
       
   854   and the second combinator to the second component, defined as
       
   855 *}
       
   856 
       
   857 ML{*fun (x, y) ||> f = (x, f y)*}
       
   858 
       
   859 text {*
       
   860   With the combinator @{ML "|->"} you can re-combine the elements from a pair.
       
   861   This combinator is defined as
       
   862 *}
       
   863 
       
   864 ML{*fun (x, y) |-> f = f x y*}
       
   865 
       
   866 text {* and can be used to write the following roundabout version 
       
   867   of the @{text double} function: 
       
   868 *}
       
   869 
       
   870 ML{*fun double x =
       
   871       x |>  (fn x => (x, x))
       
   872         |-> (fn x => fn y => x + y)*}
       
   873 
       
   874 text {*
       
   875   Recall that @{ML "|>"} is the reverse function applications. Recall also that the related 
       
   876   reverse function composition is @{ML "#>"}. In fact all the combinators @{ML "|->"},
       
   877   @{ML "|>>"} and @{ML "||>"} described above have related combinators for function
       
   878   composition, namely @{ML "#->"}, @{ML "#>>"} and @{ML "##>"}. Using @{ML "#->"}, 
       
   879   for example, the function @{text double} can also be written as:
       
   880 *}
       
   881 
       
   882 ML{*val double =
       
   883             (fn x => (x, x))
       
   884         #-> (fn x => fn y => x + y)*}
       
   885 
       
   886 text {*
       
   887   
       
   888   (FIXME: find a good exercise for combinators)
       
   889 *}
       
   890 
       
   891 
   910 
   892 (*<*)
   911 (*<*)
   893 setup {*
   912 setup {*
   894  Sign.add_consts_i [("bar", @{typ "nat"},NoSyn)] 
   913  Sign.add_consts_i [("bar", @{typ "nat"},NoSyn)] 
   895 *}
   914 *}