CookBook/FirstSteps.thy
changeset 82 6dfe6975bda0
parent 81 8fda6b452f28
child 84 624279d187e1
equal deleted inserted replaced
81:8fda6b452f28 82:6dfe6975bda0
   508 *}
   508 *}
   509 
   509 
   510 section {* Combinators\label{sec:combinators} *}
   510 section {* Combinators\label{sec:combinators} *}
   511 
   511 
   512 text {*
   512 text {*
   513   Perhaps one of the most puzzling aspect for a beginner when reading  
   513   For beginners, perhaps the most puzzling parts in the existing code of Isabelle are
   514   existing Isabelle code special purpose combinators. At first they 
   514   the combinators. At first they seem to greatly obstruct the
   515   seem to obstruct the comprehension of the code, but after getting familiar 
   515   comprehension of the code, but after getting familiar with them, they
   516   with them they actually ease the understanding and also the programming.
   516   actually ease the understanding and also the programming.
   517 
   517 
   518   \begin{readmore}
   518   \begin{readmore}
   519   The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"}
   519   The most frequently used combinator are defined in the files @{ML_file "Pure/library.ML"}
   520   and @{ML_file "Pure/General/basics.ML"}.
   520   and @{ML_file "Pure/General/basics.ML"}.
   521   \end{readmore}
   521   \end{readmore}
   523   The simplest combinator is @{ML I} which is just the identity function.
   523   The simplest combinator is @{ML I} which is just the identity function.
   524 *}
   524 *}
   525 
   525 
   526 ML{*fun I x = x*}
   526 ML{*fun I x = x*}
   527 
   527 
   528 text {* Another combinator is @{ML K}, defined as *}
   528 text {* Another simple combinator is @{ML K}, defined as *}
   529 
   529 
   530 ML{*fun K x = fn _ => x*}
   530 ML{*fun K x = fn _ => x*}
   531 
   531 
   532 text {*
   532 text {*
   533   It ``wraps'' a function around the argument @{text "x"}. However, this 
   533   It ``wraps'' a function around the argument @{text "x"}. However, this 
   534   function ignores its argument. 
   534   function ignores its argument. So @{ML K} defines a constant function 
   535 
   535   returning @{text x}.
   536   The next combinator is reverse application, @{ML "(op |>)"}, defined as 
   536 
       
   537   The next combinator is reverse application, @{ML "|>"}, defined as 
   537 *}
   538 *}
   538 
   539 
   539 ML{*fun x |> f = f x*}
   540 ML{*fun x |> f = f x*}
   540 
   541 
   541 text {* While just syntactic sugar for the usual function application,
   542 text {* While just syntactic sugar for the usual function application,
   552   which increments the argument @{text x} by 5. It does this by first incrementing 
   553   which increments the argument @{text x} by 5. It does this by first incrementing 
   553   the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking 
   554   the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking 
   554   the first component of the pair (Line 4) and finally incrementing the first 
   555   the first component of the pair (Line 4) and finally incrementing the first 
   555   component by 4 (Line 5). This kind of cascading manipulations of values is quite
   556   component by 4 (Line 5). This kind of cascading manipulations of values is quite
   556   common when dealing with theories (for example by adding a definition, followed by
   557   common when dealing with theories (for example by adding a definition, followed by
   557   lemmas and so on). Writing the function @{ML inc_by_five} using the reverse
   558   lemmas and so on). It should also be familiar to anyone who has used Haskell's
       
   559   do-notation. Writing the function @{ML inc_by_five} using the reverse
   558   application is much clearer than writing
   560   application is much clearer than writing
   559 *}
   561 *}
   560 
   562 
   561 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*}
   563 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*}
   562 
   564 
   573        val y3 = fst y2
   575        val y3 = fst y2
   574        val y4 = y3 + 4
   576        val y4 = y3 + 4
   575    in y4 end*}
   577    in y4 end*}
   576 
   578 
   577 text {* 
   579 text {* 
       
   580   Another reason why the let-bindings in the code above are better to be
       
   581   avoided: it is more than easy to get the intermediate values wrong!
       
   582 
       
   583 
   578   (FIXME: give a real world example involving theories)
   584   (FIXME: give a real world example involving theories)
   579 
   585 
   580   Similarly, the combinator @{ML "(op #>)"} is the reverse function 
   586   Similarly, the combinator @{ML "#>"} is the reverse function 
   581   composition. It can be used to define functions as follows
   587   composition. It can be used to define functions as follows
   582 *}
   588 *}
   583 
   589 
   584 ML{*val inc_by_six = 
   590 ML{*val inc_by_six = 
   585       (fn x => x + 1)
   591       (fn x => x + 1)
   586    #> (fn x => x + 2)
   592    #> (fn x => x + 2)
   587    #> (fn x => x + 3)*}
   593    #> (fn x => x + 3)*}
   588 
   594 
   589 text {* 
   595 text {* 
   590   which is the function composed of first the increment-by-one function and then
   596   which is the function composed of first the increment-by-one function and then
   591   increment-by-two, followed by increment-by-three. Applying 6 to this function 
   597   increment-by-two, followed by increment-by-three. 
   592   yields
   598 
   593 
   599   The remaining combinators described in this section add convenience for the
   594   @{ML_response [display,gray] "inc_by_six 6" "12"}
   600   ``waterfall method'' of writing functions. The combinator @{ML tap} allows
   595 
   601   one to get hold of an intermediate result (to do some side-calculations for
   596   as expected.
   602   instance). The function
   597 
   603 
   598   The remaining combinators add convenience for the ``waterfall method''
   604  *}
   599   of writing functions. The combinator @{ML tap} allows one to get 
   605 
   600   hold of an intermediate result (to do some side-calculations for instance). 
   606 ML %linenumbers{*fun inc_by_three x =
   601   The function *}
       
   602 
       
   603 ML{*fun inc_by_three x =
       
   604      x |> (fn x => x + 1)
   607      x |> (fn x => x + 1)
   605        |> tap (fn x => tracing (makestring x))
   608        |> tap (fn x => tracing (makestring x))
   606        |> (fn x => x + 2)*}
   609        |> (fn x => x + 2)*}
   607 
   610 
   608 text {* increments the argument first by one and then by two. In the middle,
   611 text {* increments the argument first by one and then by two. In the middle,
   609   however, it uses @{ML tap} for printing the ``plus-one'' intermediate 
   612   however, it uses @{ML tap} for printing the ``plus-one'' intermediate 
   610   result inside the tracing buffer.
   613   result inside the tracing buffer (Line 3). The function @{ML tap} can only
   611 
   614   be used for side-calculations, because any value that is computed cannot
   612   The combinator @{ML "(op `)"} is similar, but applies a function to the value
   615   be merged back into the ``main waterfall''. To do this, the next combinator
   613   and returns the result together with the original value (as pair). For example
   616   can be used.
   614   the following function takes @{text x} as argument, and then first 
   617 
   615   increments @{text x}, but also keeps @{text x}. The intermediate result is 
   618   The combinator @{ML "`"} is similar to @{ML tap}, but applies a function to the value
   616   therefore the pair @{ML "(x + 1,x)" for x}. The function then increments the 
   619   and returns the result together with the value (as a pair). For example
   617   right-hand component of the pair.
   620   the function 
   618 *}
   621 *}
   619 
   622 
   620 ML{*fun inc_as_pair x =
   623 ML{*fun inc_as_pair x =
   621      x |> `(fn x => x + 1)
   624      x |> `(fn x => x + 1)
   622        |> (fn (x, y) => (x, y + 1))*}
   625        |> (fn (x, y) => (x, y + 1))*}
   623 
   626 
   624 text {*
   627 text {*
   625   The combinators @{ML "(op |>>)"} and @{ML "(op ||>)"} are defined for 
   628   takes @{text x} as argument, and then first 
       
   629   increments @{text x}, but also keeps @{text x}. The intermediate result is 
       
   630   therefore the pair @{ML "(x + 1, x)" for x}. The function then increments the 
       
   631   right-hand component of the pair. So finally the result will be 
       
   632   @{ML "(x + 1, x + 1)" for x}.
       
   633 
       
   634   The combinators @{ML "|>>"} and @{ML "||>"} are defined for 
   626   functions manipulating pairs. The first applies the function to
   635   functions manipulating pairs. The first applies the function to
   627   the first component of the pair, defined as:
   636   the first component of the pair, defined as:
   628 *}
   637 *}
   629 
   638 
   630 ML{*fun (x, y) |>> f = (f x, y)*}
   639 ML{*fun (x, y) |>> f = (f x, y)*}
   634 *}
   643 *}
   635 
   644 
   636 ML{*fun (x, y) ||> f = (x, f y)*}
   645 ML{*fun (x, y) ||> f = (x, f y)*}
   637 
   646 
   638 text {*
   647 text {*
       
   648   With the combinator @{ML "|->"} you can re-combine the elements from a pair.
       
   649   This combinator is defined as
       
   650 *}
       
   651 
       
   652 ML{*fun (x, y) |-> f = f x y*}
       
   653 
       
   654 text {* and can be used to write the following version of the @{text double} function *}
       
   655 
       
   656 ML{*fun double x =
       
   657       x |>  (fn x => (x, x))
       
   658         |-> (fn x => fn y => x + y)*}
       
   659 
       
   660 text {*
       
   661   Recall that @{ML "|>"} is the reverse function applications. The related 
       
   662   reverse function composition is @{ML "#>"}. In fact all combinators @{ML "|->"},
       
   663   @{ML "|>>"} and @{ML "||>"} described above have related combinators for function
       
   664   composition, namely @{ML "#->"}, @{ML "#>>"} and @{ML "##>"}. In this
       
   665   way, the function @{text double} can also be written as
       
   666 *}
       
   667 
       
   668 ML{*val double =
       
   669             (fn x => (x, x))
       
   670         #-> (fn x => fn y => x + y)*}
       
   671   
       
   672 
       
   673 text {*
       
   674   
       
   675 
       
   676 
   639   (FIXME: find a good exercise for combinators)
   677   (FIXME: find a good exercise for combinators)
   640 *}
   678 *}
   641 
   679 
   642 end
   680 end