doc-src/IsarAdvanced/Functions/Thy/Functions.thy
changeset 23003 4b0bf04a4d68
parent 22065 cdd077905eee
child 23188 595a0e24bd8e
equal deleted inserted replaced
23002:b469cf6dc531 23003:4b0bf04a4d68
     7 
     7 
     8 theory Functions
     8 theory Functions
     9 imports Main
     9 imports Main
    10 begin
    10 begin
    11 
    11 
    12 chapter {* Defining Recursive Functions in Isabelle/HOL *}
       
    13 
       
    14 section {* Function Definition for Dummies *}
    12 section {* Function Definition for Dummies *}
    15 
    13 
    16 text {*
    14 text {*
    17   In most cases, defining a recursive function is just as simple as other definitions:
    15   In most cases, defining a recursive function is just as simple as other definitions:
    18   *}
    16 
       
    17   Like in functional programming, a function definition consists of a 
       
    18 
       
    19 *}
    19 
    20 
    20 fun fib :: "nat \<Rightarrow> nat"
    21 fun fib :: "nat \<Rightarrow> nat"
    21 where
    22 where
    22   "fib 0 = 1"
    23   "fib 0 = 1"
    23 | "fib (Suc 0) = 1"
    24 | "fib (Suc 0) = 1"
    24 | "fib (Suc (Suc n)) = fib n + fib (Suc n)"
    25 | "fib (Suc (Suc n)) = fib n + fib (Suc n)"
    25 
    26 
    26 text {*
    27 text {*
    27   The function always terminates, since the argument of gets smaller in every
    28   The syntax is rather self-explanatory: We introduce a function by
    28   recursive call. Termination is an
    29   giving its name, its type and a set of defining recursive
    29   important requirement, since it prevents inconsistencies: From
    30   equations. 
    30   the "definition" @{text "f(n) = f(n) + 1"} we could prove 
    31 *}
    31   @{text "0  = 1"} by subtracting @{text "f(n)"} on both sides.
    32 
       
    33 
       
    34 
       
    35 
       
    36 
       
    37 text {*
       
    38   The function always terminates, since its argument gets smaller in
       
    39   every recursive call. Termination is an important requirement, since
       
    40   it prevents inconsistencies: From the "definition" @{text "f(n) =
       
    41   f(n) + 1"} we could prove @{text "0 = 1"} by subtracting @{text
       
    42   "f(n)"} on both sides.
    32 
    43 
    33   Isabelle tries to prove termination automatically when a function is
    44   Isabelle tries to prove termination automatically when a function is
    34   defined. We will later look at cases where this fails and see what to
    45   defined. We will later look at cases where this fails and see what to
    35   do then.
    46   do then.
    36 *}
    47 *}
    37 
    48 
    38 subsection {* Pattern matching *}
    49 subsection {* Pattern matching *}
    39 
    50 
    40 text {* \label{patmatch}
    51 text {* \label{patmatch}
    41   Like in functional programming, functions can be defined by pattern
    52   Like in functional programming, we can use pattern matching to
    42   matching. At the moment we will only consider \emph{datatype
    53   define functions. At the moment we will only consider \emph{constructor
    43   patterns}, which only consist of datatype constructors and
    54   patterns}, which only consist of datatype constructors and
    44   variables.
    55   variables.
    45 
    56 
    46   If patterns overlap, the order of the equations is taken into
    57   If patterns overlap, the order of the equations is taken into
    47   account. The following function inserts a fixed element between any
    58   account. The following function inserts a fixed element between any
    69   simplification:
    80   simplification:
    70 *}
    81 *}
    71 
    82 
    72 lemma "sep (0::nat) [1, 2, 3] = [1, 0, 2, 0, 3]"
    83 lemma "sep (0::nat) [1, 2, 3] = [1, 0, 2, 0, 3]"
    73 by simp
    84 by simp
    74 
       
    75   
       
    76 
    85 
    77 subsection {* Induction *}
    86 subsection {* Induction *}
    78 
    87 
    79 text {*
    88 text {*
    80 
    89 
   176   @{text "N + 1 - i"} decreases in every recursive call.
   185   @{text "N + 1 - i"} decreases in every recursive call.
   177 
   186 
   178   We can use this expression as a measure function suitable to prove termination.
   187   We can use this expression as a measure function suitable to prove termination.
   179 *}
   188 *}
   180 
   189 
   181 termination 
   190 termination sum
   182 by (relation "measure (\<lambda>(i,N). N + 1 - i)") auto
   191 by (relation "measure (\<lambda>(i,N). N + 1 - i)") auto
   183 
   192 
   184 text {*
   193 text {*
       
   194   The \cmd{termination} command sets up the termination goal for the
       
   195   specified function @{text "sum"}. If the function name is omitted it
       
   196   implicitly refers to the last function definition.
       
   197 
   185   The @{text relation} method takes a relation of
   198   The @{text relation} method takes a relation of
   186   type @{typ "('a \<times> 'a) set"}, where @{typ "'a"} is the argument type of
   199   type @{typ "('a \<times> 'a) set"}, where @{typ "'a"} is the argument type of
   187   the function. If the function has multiple curried arguments, then
   200   the function. If the function has multiple curried arguments, then
   188   these are packed together into a tuple, as it happened in the above
   201   these are packed together into a tuple, as it happened in the above
   189   example.
   202   example.
   221 *}
   234 *}
   222 
   235 
   223 termination 
   236 termination 
   224 by (relation "measures [\<lambda>(i, N). N, \<lambda>(i,N). N + 1 - i]") auto
   237 by (relation "measures [\<lambda>(i, N). N, \<lambda>(i,N). N + 1 - i]") auto
   225 
   238 
       
   239 subsection {* Manual Termination Proofs *}
       
   240 
       
   241 text {*
       
   242   The @{text relation} method is often useful, but not
       
   243   necessary. Since termination proofs are just normal Isabelle proofs,
       
   244   they can also be carried out manually: 
       
   245 *}
       
   246 
       
   247 function id :: "nat \<Rightarrow> nat"
       
   248 where
       
   249   "id 0 = 0"
       
   250 | "id (Suc n) = Suc (id n)"
       
   251 by pat_completeness auto
       
   252 
       
   253 termination
       
   254 proof 
       
   255   show "wf less_than" ..
       
   256 next
       
   257   fix n show "(n, Suc n) \<in> less_than" by simp
       
   258 qed
       
   259 
       
   260 text {*
       
   261   Of course this is just a trivial example, but manual proofs can
       
   262   sometimes be the only choice if faced with very hard termination problems.
       
   263 *}
       
   264 
   226 
   265 
   227 section {* Mutual Recursion *}
   266 section {* Mutual Recursion *}
   228 
   267 
   229 text {*
   268 text {*
   230   If two or more functions call one another mutually, they have to be defined
   269   If two or more functions call one another mutually, they have to be defined
   332   This splitting can significantly increase the number of equations
   371   This splitting can significantly increase the number of equations
   333   involved, and is not always necessary. The following simple example
   372   involved, and is not always necessary. The following simple example
   334   shows the problem:
   373   shows the problem:
   335   
   374   
   336   Suppose we are modelling incomplete knowledge about the world by a
   375   Suppose we are modelling incomplete knowledge about the world by a
   337   three-valued datatype, which has values for @{term "T"}, @{term "F"}
   376   three-valued datatype, which has values @{term "T"}, @{term "F"}
   338   and @{term "X"} for true, false and uncertain propositions. 
   377   and @{term "X"} for true, false and uncertain propositions, respectively. 
   339 *}
   378 *}
   340 
   379 
   341 datatype P3 = T | F | X
   380 datatype P3 = T | F | X
   342 
   381 
   343 text {* Then the conjunction of such values can be defined as follows: *}
   382 text {* Then the conjunction of such values can be defined as follows: *}
   344 
   383 
   345 fun And :: "P3 \<Rightarrow> P3 \<Rightarrow> P3"
   384 fun And :: "P3 \<Rightarrow> P3 \<Rightarrow> P3"
   346 where
   385 where
   347   "And T p = p"
   386   "And T p = p"
   348   "And p T = p"
   387 | "And p T = p"
   349   "And p F = F"
   388 | "And p F = F"
   350   "And F p = F"
   389 | "And F p = F"
   351   "And X X = X"
   390 | "And X X = X"
   352 
   391 
   353 
   392 
   354 text {* 
   393 text {* 
   355   This definition is useful, because the equations can directly be used
   394   This definition is useful, because the equations can directly be used
   356   as rules to simplify expressions. But the patterns overlap, e.g.~the
   395   as rules to simplify expressions. But the patterns overlap, e.g.~the
   363 
   402 
   364 text {*
   403 text {*
   365   @{thm[indent=4] And.simps}
   404   @{thm[indent=4] And.simps}
   366   
   405   
   367   \vspace*{1em}
   406   \vspace*{1em}
   368   \noindent There are several problems with this approach:
   407   \noindent There are several problems with this:
   369 
   408 
   370   \begin{enumerate}
   409   \begin{enumerate}
   371   \item When datatypes have many constructors, there can be an
   410   \item When datatypes have many constructors, there can be an
   372   explosion of equations. For @{const "And"}, we get seven instead of
   411   explosion of equations. For @{const "And"}, we get seven instead of
   373   five equation, which can be tolerated, but this is just a small
   412   five equations, which can be tolerated, but this is just a small
   374   example.
   413   example.
   375 
   414 
   376   \item Since splitting makes the equations "more special", they
   415   \item Since splitting makes the equations "less general", they
   377   do not always match in rewriting. While the term @{term "And x F"}
   416   do not always match in rewriting. While the term @{term "And x F"}
   378   can be simplified to @{term "F"} by the original specification, a
   417   can be simplified to @{term "F"} by the original specification, a
   379   (manual) case split on @{term "x"} is now necessary.
   418   (manual) case split on @{term "x"} is now necessary.
   380 
   419 
   381   \item The splitting also concerns the induction rule @{text
   420   \item The splitting also concerns the induction rule @{text
   388 
   427 
   389   On the other hand, a definition needs to be consistent and defining
   428   On the other hand, a definition needs to be consistent and defining
   390   both @{term "f x = True"} and @{term "f x = False"} is a bad
   429   both @{term "f x = True"} and @{term "f x = False"} is a bad
   391   idea. So if we don't want Isabelle to mangle our definitions, we
   430   idea. So if we don't want Isabelle to mangle our definitions, we
   392   will have to prove that this is not necessary. By using the full
   431   will have to prove that this is not necessary. By using the full
   393   definition form withour the \cmd{sequential} option, we get this
   432   definition form without the \cmd{sequential} option, we get this
   394   behaviour: 
   433   behaviour: 
   395 *}
   434 *}
   396 
   435 
   397 function And2 :: "P3 \<Rightarrow> P3 \<Rightarrow> P3"
   436 function And2 :: "P3 \<Rightarrow> P3 \<Rightarrow> P3"
   398 where
   437 where
   399   "And2 T p = p"
   438   "And2 T p = p"
   400   "And2 p T = p"
   439 | "And2 p T = p"
   401   "And2 p F = F"
   440 | "And2 p F = F"
   402   "And2 F p = F"
   441 | "And2 F p = F"
   403   "And2 X X = X"
   442 | "And2 X X = X"
   404 
   443 
   405 txt {*
   444 txt {*
   406   Now it is also time to look at the subgoals generated by a
   445   Now it is also time to look at the subgoals generated by a
   407   function definition. In this case, they are:
   446   function definition. In this case, they are:
   408 
   447 
   434 subsection {* Non-constructor patterns *}
   473 subsection {* Non-constructor patterns *}
   435 
   474 
   436 text {* FIXME *}
   475 text {* FIXME *}
   437 
   476 
   438 
   477 
   439 subsection {* Non-constructor patterns *}
       
   440 
       
   441 text {* FIXME *}
       
   442 
       
   443 
       
   444 
       
   445 
       
   446 
   478 
   447 
   479 
   448 section {* Partiality *}
   480 section {* Partiality *}
   449 
   481 
   450 text {* 
   482 text {* 
   451   In HOL, all functions are total. A function @{term "f"} applied to
   483   In HOL, all functions are total. A function @{term "f"} applied to
   452   @{term "x"} always has a value @{term "f x"}, and there is no notion
   484   @{term "x"} always has a value @{term "f x"}, and there is no notion
   453   of undefinedness. 
   485   of undefinedness. 
   454 
       
   455   FIXME
       
   456 *}
       
   457 
       
   458 
       
   459 
       
   460   
   486   
       
   487   This property of HOL is the reason why we have to do termination
       
   488   proofs when defining functions: The termination proof justifies the
       
   489   definition of the function by wellfounded recursion.
       
   490 
       
   491   However, the \cmd{function} package still supports partiality. Let's
       
   492   look at the following function which searches for a zero in the
       
   493   function f. 
       
   494 *}
       
   495 
       
   496 function (*<*)(domintros, tailrec)(*>*)findzero :: "(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat"
       
   497 where
       
   498   "findzero f n = (if f n = 0 then n else findzero f (Suc n))"
       
   499 by pat_completeness auto
       
   500 (*<*)declare findzero.simps[simp del](*>*)
       
   501 
       
   502 text {*
       
   503   Clearly, any attempt of a termination proof must fail. And without
       
   504   that, we do not get the usual rules @{text "findzero.simp"} and 
       
   505   @{text "findzero.induct"}. So what was the definition good for at all?
       
   506 *}
       
   507 
       
   508 subsection {* Domain predicates *}
       
   509 
       
   510 text {*
       
   511   The trick is that Isabelle has not only defined the function @{const findzero}, but also
       
   512   a predicate @{term "findzero_dom"} that characterizes the values where the function
       
   513   terminates: the \emph{domain} of the function. In Isabelle/HOL, a
       
   514   partial function is just a total function with an additional domain
       
   515   predicate. Like with total functions, we get simplification and
       
   516   induction rules, but they are guarded by the domain conditions and
       
   517   called @{text psimps} and @{text pinduct}:
       
   518 *}
       
   519 
       
   520 thm findzero.psimps
       
   521 
       
   522 text {*
       
   523   @{thm[display] findzero.psimps}
       
   524 *}
       
   525 
       
   526 thm findzero.pinduct
       
   527 
       
   528 text {*
       
   529   @{thm[display] findzero.pinduct}
       
   530 *}
       
   531 
       
   532 text {*
       
   533   As already mentioned, HOL does not support true partiality. All we
       
   534   are doing here is using some tricks to make a total function appear
       
   535   as if it was partial. We can still write the term @{term "findzero
       
   536   (\<lambda>x. 1) 0"} and like any other term of type @{typ nat} it is equal
       
   537   to some natural number, although we might not be able to find out
       
   538   which one (we will discuss this further in \S\ref{default}). The
       
   539   function is \emph{underdefined}.
       
   540 
       
   541   But it is enough defined to prove something about it. We can prove
       
   542   that if @{term "findzero f n"}
       
   543   it terminates, it indeed returns a zero of @{term f}:
       
   544 *}
       
   545 
       
   546 lemma findzero_zero: "findzero_dom (f, n) \<Longrightarrow> f (findzero f n) = 0"
       
   547 
       
   548 txt {* We apply induction as usual, but using the partial induction
       
   549   rule: *}
       
   550 
       
   551 apply (induct f n rule: findzero.pinduct)
       
   552 
       
   553 txt {* This gives the following subgoals:
       
   554 
       
   555   @{subgoals[display,indent=0]}
       
   556 
       
   557   The premise in our lemma was used to satisfy the first premise in
       
   558   the induction rule. However, now we can also use @{term
       
   559   "findzero_dom (f, n)"} as an assumption in the induction step. This
       
   560   allows to unfold @{term "findzero f n"} using the @{text psimps}
       
   561   rule, and the rest is trivial. Since @{text psimps} rules carry the
       
   562   @{text "[simp]"} attribute by default, we just need a single step:
       
   563  *}
       
   564 apply simp
       
   565 done
       
   566 
       
   567 text {*
       
   568   Proofs about partial functions are often not harder than for total
       
   569   functions. Fig.~\ref{findzero_isar} shows a slightly more
       
   570   complicated proof written in Isar. It is verbose enough to show how
       
   571   partiality comes into play: From the partial induction, we get an
       
   572   additional domain condition hypothesis. Observe how this condition
       
   573   is applied when calls to @{term findzero} are unfolded.
       
   574 *}
       
   575 
       
   576 text_raw {*
       
   577 \begin{figure}
       
   578 \begin{center}
       
   579 \begin{minipage}{0.8\textwidth}
       
   580 \isabellestyle{it}
       
   581 \isastyle\isamarkuptrue
       
   582 *}
       
   583 lemma "\<lbrakk>findzero_dom (f, n); x \<in> {n ..< findzero f n}\<rbrakk> \<Longrightarrow> f x \<noteq> 0"
       
   584 proof (induct rule: findzero.pinduct)
       
   585   fix f n assume dom: "findzero_dom (f, n)"
       
   586     and IH: "\<lbrakk>f n \<noteq> 0; x \<in> {Suc n..<findzero f (Suc n)}\<rbrakk>
       
   587              \<Longrightarrow> f x \<noteq> 0"
       
   588     and x_range: "x \<in> {n..<findzero f n}"
       
   589   
       
   590   have "f n \<noteq> 0"
       
   591   proof 
       
   592     assume "f n = 0"
       
   593     with dom have "findzero f n = n" by simp
       
   594     with x_range show False by auto
       
   595   qed
       
   596   
       
   597   from x_range have "x = n \<or> x \<in> {Suc n ..< findzero f n}" by auto
       
   598   thus "f x \<noteq> 0"
       
   599   proof
       
   600     assume "x = n"
       
   601     with `f n \<noteq> 0` show ?thesis by simp
       
   602   next
       
   603     assume "x \<in> {Suc n..<findzero f n}"
       
   604     with dom and `f n \<noteq> 0` have "x \<in> {Suc n ..< findzero f (Suc n)}"
       
   605       by simp
       
   606     with IH and `f n \<noteq> 0`
       
   607     show ?thesis by simp
       
   608   qed
       
   609 qed
       
   610 text_raw {*
       
   611 \isamarkupfalse\isabellestyle{tt}
       
   612 \end{minipage}\end{center}
       
   613 \caption{A proof about a partial function}\label{findzero_isar}
       
   614 \end{figure}
       
   615 *}
       
   616 
       
   617 subsection {* Partial termination proofs *}
       
   618 
       
   619 text {*
       
   620   Now that we have proved some interesting properties about our
       
   621   function, we should turn to the domain predicate and see if it is
       
   622   actually true for some values. Otherwise we would have just proved
       
   623   lemmas with @{term False} as a premise.
       
   624 
       
   625   Essentially, we need some introduction rules for @{text
       
   626   findzero_dom}. The function package can prove such domain
       
   627   introduction rules automatically. But since they are not used very
       
   628   often (they are almost never needed if the function is total), they
       
   629   are disabled by default for efficiency reasons. So we have to go
       
   630   back and ask for them explicitly by passing the @{text
       
   631   "(domintros)"} option to the function package:
       
   632 
       
   633 \noindent\cmd{function} @{text "(domintros) findzero :: \"(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat\""}\\%
       
   634 \cmd{where}\isanewline%
       
   635 \ \ \ldots\\
       
   636 \cmd{by} @{text "pat_completeness auto"}\\%
       
   637 
       
   638 
       
   639   Now the package has proved an introduction rule for @{text findzero_dom}:
       
   640 *}
       
   641 
       
   642 thm findzero.domintros
       
   643 
       
   644 text {*
       
   645   @{thm[display] findzero.domintros}
       
   646 
       
   647   Domain introduction rules allow to show that a given value lies in the
       
   648   domain of a function, if the arguments of all recursive calls
       
   649   are in the domain as well. They allow to do a \qt{single step} in a
       
   650   termination proof. Usually, you want to combine them with a suitable
       
   651   induction principle.
       
   652 
       
   653   Since our function increases its argument at recursive calls, we
       
   654   need an induction principle which works \qt{backwards}. We will use
       
   655   @{text inc_induct}, which allows to do induction from a fixed number
       
   656   \qt{downwards}:
       
   657 
       
   658   @{thm[display] inc_induct}
       
   659 
       
   660   Fig.~\ref{findzero_term} gives a detailed Isar proof of the fact
       
   661   that @{text findzero} terminates if there is a zero which is greater
       
   662   or equal to @{term n}. First we derive two useful rules which will
       
   663   solve the base case and the step case of the induction. The
       
   664   induction is then straightforward, except for the unusal induction
       
   665   principle.
       
   666 
       
   667 *}
       
   668 
       
   669 text_raw {*
       
   670 \begin{figure}
       
   671 \begin{center}
       
   672 \begin{minipage}{0.8\textwidth}
       
   673 \isabellestyle{it}
       
   674 \isastyle\isamarkuptrue
       
   675 *}
       
   676 lemma findzero_termination:
       
   677   assumes "x >= n" 
       
   678   assumes "f x = 0"
       
   679   shows "findzero_dom (f, n)"
       
   680 proof - 
       
   681   have base: "findzero_dom (f, x)"
       
   682     by (rule findzero.domintros) (simp add:`f x = 0`)
       
   683 
       
   684   have step: "\<And>i. findzero_dom (f, Suc i) 
       
   685     \<Longrightarrow> findzero_dom (f, i)"
       
   686     by (rule findzero.domintros) simp
       
   687 
       
   688   from `x \<ge> n`
       
   689   show ?thesis
       
   690   proof (induct rule:inc_induct)
       
   691     show "findzero_dom (f, x)"
       
   692       by (rule base)
       
   693   next
       
   694     fix i assume "findzero_dom (f, Suc i)"
       
   695     thus "findzero_dom (f, i)"
       
   696       by (rule step)
       
   697   qed
       
   698 qed      
       
   699 text_raw {*
       
   700 \isamarkupfalse\isabellestyle{tt}
       
   701 \end{minipage}\end{center}
       
   702 \caption{Termination proof for @{text findzero}}\label{findzero_term}
       
   703 \end{figure}
       
   704 *}
       
   705       
       
   706 text {*
       
   707   Again, the proof given in Fig.~\ref{findzero_term} has a lot of
       
   708   detail in order to explain the principles. Using more automation, we
       
   709   can also have a short proof:
       
   710 *}
       
   711 
       
   712 lemma findzero_termination_short:
       
   713   assumes zero: "x >= n" 
       
   714   assumes [simp]: "f x = 0"
       
   715   shows "findzero_dom (f, n)"
       
   716   using zero
       
   717   by (induct rule:inc_induct) (auto intro: findzero.domintros)
       
   718     
       
   719 text {*
       
   720   It is simple to combine the partial correctness result with the
       
   721   termination lemma:
       
   722 *}
       
   723 
       
   724 lemma findzero_total_correctness:
       
   725   "f x = 0 \<Longrightarrow> f (findzero f 0) = 0"
       
   726 by (blast intro: findzero_zero findzero_termination)
       
   727 
       
   728 subsection {* Definition of the domain predicate *}
       
   729 
       
   730 text {*
       
   731   Sometimes it is useful to know what the definition of the domain
       
   732   predicate actually is. Actually, @{text findzero_dom} is just an
       
   733   abbreviation:
       
   734 
       
   735   @{abbrev[display] findzero_dom}
       
   736 
       
   737   The domain predicate is the accessible part of a relation @{const
       
   738   findzero_rel}, which was also created internally by the function
       
   739   package. @{const findzero_rel} is just a normal
       
   740   inductively defined predicate, so we can inspect its definition by
       
   741   looking at the introduction rules @{text findzero_rel.intros}.
       
   742   In our case there is just a single rule:
       
   743 
       
   744   @{thm[display] findzero_rel.intros}
       
   745 
       
   746   The relation @{const findzero_rel}, expressed as a binary predicate,
       
   747   describes the \emph{recursion relation} of the function
       
   748   definition. The recursion relation is a binary relation on
       
   749   the arguments of the function that relates each argument to its
       
   750   recursive calls. In general, there is one introduction rule for each
       
   751   recursive call.
       
   752 
       
   753   The predicate @{term "acc findzero_rel"} is the \emph{accessible part} of
       
   754   that relation. An argument belongs to the accessible part, if it can
       
   755   be reached in a finite number of steps. 
       
   756 
       
   757   Since the domain predicate is just an abbreviation, you can use
       
   758   lemmas for @{const acc} and @{const findzero_rel} directly. Some
       
   759   lemmas which are occasionally useful are @{text accI}, @{text
       
   760   acc_downward}, and of course the introduction and elimination rules
       
   761   for the recursion relation @{text "findzero.intros"} and @{text "findzero.cases"}.
       
   762 *}
       
   763 
       
   764 (*lemma findzero_nicer_domintros:
       
   765   "f x = 0 \<Longrightarrow> findzero_dom (f, x)"
       
   766   "findzero_dom (f, Suc x) \<Longrightarrow> findzero_dom (f, x)"
       
   767 by (rule accI, erule findzero_rel.cases, auto)+
       
   768 *)
       
   769   
       
   770 subsection {* A Useful Special Case: Tail recursion *}
       
   771 
       
   772 text {*
       
   773   The domain predicate is our trick that allows us to model partiality
       
   774   in a world of total functions. The downside of this is that we have
       
   775   to carry it around all the time. The termination proof above allowed
       
   776   us to replace the abstract @{term "findzero_dom (f, n)"} by the more
       
   777   concrete @{term "(x \<ge> n \<and> f x = 0)"}, but the condition is still
       
   778   there and it won't go away soon. 
       
   779 
       
   780   In particular, the domain predicate guard the unfolding of our
       
   781   function, since it is there as a condition in the @{text psimp}
       
   782   rules. 
       
   783 
       
   784   On the other hand, we must be happy about the domain predicate,
       
   785   since it guarantees that all this is at all possible without losing
       
   786   consistency. 
       
   787 
       
   788   Now there is an important special case: We can actually get rid
       
   789   of the condition in the simplification rules, \emph{if the function
       
   790   is tail-recursive}. The reason is that for all tail-recursive
       
   791   equations there is a total function satisfying them, even if they
       
   792   are non-terminating. 
       
   793 
       
   794   The function package internally does the right construction and can
       
   795   derive the unconditional simp rules, if we ask it to do so. Luckily,
       
   796   our @{const "findzero"} function is tail-recursive, so we can just go
       
   797   back and add another option to the \cmd{function} command:
       
   798 
       
   799 \noindent\cmd{function} @{text "(domintros, tailrec) findzero :: \"(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat\""}\\%
       
   800 \cmd{where}\isanewline%
       
   801 \ \ \ldots\\%
       
   802 
       
   803   
       
   804   Now, we actually get the unconditional simplification rules, even
       
   805   though the function is partial:
       
   806 *}
       
   807 
       
   808 thm findzero.simps
       
   809 
       
   810 text {*
       
   811   @{thm[display] findzero.simps}
       
   812 
       
   813   Of course these would make the simplifier loop, so we better remove
       
   814   them from the simpset:
       
   815 *}
       
   816 
       
   817 declare findzero.simps[simp del]
       
   818 
       
   819 
       
   820 text {* \fixme{Code generation ???} *}
       
   821 
   461 section {* Nested recursion *}
   822 section {* Nested recursion *}
   462 
   823 
   463 text {*
   824 text {*
       
   825   Recursive calls which are nested in one another frequently cause
       
   826   complications, since their termination proof can depend on a partial
       
   827   correctness property of the function itself. 
       
   828 
       
   829   As a small example, we define the \qt{nested zero} function:
       
   830 *}
       
   831 
       
   832 function nz :: "nat \<Rightarrow> nat"
       
   833 where
       
   834   "nz 0 = 0"
       
   835 | "nz (Suc n) = nz (nz n)"
       
   836 by pat_completeness auto
       
   837 
       
   838 text {*
       
   839   If we attempt to prove termination using the identity measure on
       
   840   naturals, this fails:
       
   841 *}
       
   842 
       
   843 termination
       
   844   apply (relation "measure (\<lambda>n. n)")
       
   845   apply auto
       
   846 
       
   847 txt {*
       
   848   We get stuck with the subgoal
       
   849 
       
   850   @{subgoals[display]}
       
   851 
       
   852   Of course this statement is true, since we know that @{const nz} is
       
   853   the zero function. And in fact we have no problem proving this
       
   854   property by induction.
       
   855 *}
       
   856 oops
       
   857 
       
   858 lemma nz_is_zero: "nz_dom n \<Longrightarrow> nz n = 0"
       
   859   by (induct rule:nz.pinduct) auto
       
   860 
       
   861 text {*
       
   862   We formulate this as a partial correctness lemma with the condition
       
   863   @{term "nz_dom n"}. This allows us to prove it with the @{text
       
   864   pinduct} rule before we have proved termination. With this lemma,
       
   865   the termination proof works as expected:
       
   866 *}
       
   867 
       
   868 termination
       
   869   by (relation "measure (\<lambda>n. n)") (auto simp: nz_is_zero)
       
   870 
       
   871 text {*
       
   872   As a general strategy, one should prove the statements needed for
       
   873   termination as a partial property first. Then they can be used to do
       
   874   the termination proof. This also works for less trivial
       
   875   examples. Figure \ref{f91} defines the well-known 91-function by
       
   876   McCarthy \cite{?} and proves its termination.
       
   877 *}
       
   878 
       
   879 text_raw {*
       
   880 \begin{figure}
       
   881 \begin{center}
       
   882 \begin{minipage}{0.8\textwidth}
       
   883 \isabellestyle{it}
       
   884 \isastyle\isamarkuptrue
       
   885 *}
       
   886 
       
   887 function f91 :: "nat => nat"
       
   888 where
       
   889   "f91 n = (if 100 < n then n - 10 else f91 (f91 (n + 11)))"
       
   890 by pat_completeness auto
       
   891 
       
   892 lemma f91_estimate: 
       
   893   assumes trm: "f91_dom n" 
       
   894   shows "n < f91 n + 11"
       
   895 using trm by induct auto
       
   896 
       
   897 termination
       
   898 proof
       
   899   let ?R = "measure (\<lambda>x. 101 - x)"
       
   900   show "wf ?R" ..
       
   901 
       
   902   fix n :: nat assume "\<not> 100 < n" -- "Assumptions for both calls"
       
   903 
       
   904   thus "(n + 11, n) \<in> ?R" by simp -- "Inner call"
       
   905 
       
   906   assume inner_trm: "f91_dom (n + 11)" -- "Outer call"
       
   907   with f91_estimate have "n + 11 < f91 (n + 11) + 11" .
       
   908   with `\<not> 100 < n` show "(f91 (n + 11), n) \<in> ?R" by simp 
       
   909 qed
       
   910 
       
   911 text_raw {*
       
   912 \isamarkupfalse\isabellestyle{tt}
       
   913 \end{minipage}\end{center}
       
   914 \caption{McCarthy's 91-function}\label{f91}
       
   915 \end{figure}
       
   916 *}
       
   917 
       
   918 
       
   919 section {* Higher-Order Recursion *}
       
   920 
       
   921 text {*
       
   922   Higher-order recursion occurs when recursive calls
       
   923   are passed as arguments to higher-order combinators such as @{term
       
   924   map}, @{term filter} etc.
       
   925   As an example, imagine a data type of n-ary trees:
       
   926 *}
       
   927 
       
   928 datatype 'a tree = 
       
   929   Leaf 'a 
       
   930 | Branch "'a tree list"
       
   931 
       
   932 
       
   933 text {* \noindent We can define a map function for trees, using the predefined
       
   934   map function for lists. *}
   464   
   935   
   465 
   936 function treemap :: "('a \<Rightarrow> 'a) \<Rightarrow> 'a tree \<Rightarrow> 'a tree"
   466 
   937 where
   467 
   938   "treemap f (Leaf n) = Leaf (f n)"
   468 
   939 | "treemap f (Branch l) = Branch (map (treemap f) l)"
   469 
   940 by pat_completeness auto
   470  FIXME *}
   941 
   471 
   942 text {*
   472 
   943   We do the termination proof manually, to point out what happens
   473 
   944   here: 
   474 
   945 *}
   475 
   946 
   476 
   947 termination proof
       
   948   txt {*
       
   949 
       
   950   As usual, we have to give a wellfounded relation, such that the
       
   951   arguments of the recursive calls get smaller. But what exactly are
       
   952   the arguments of the recursive calls? Isabelle gives us the
       
   953   subgoals
       
   954 
       
   955   @{subgoals[display,indent=0]} 
       
   956 
       
   957   So Isabelle seems to know that @{const map} behaves nicely and only
       
   958   applies the recursive call @{term "treemap f"} to elements
       
   959   of @{term "l"}. Before we discuss where this knowledge comes from,
       
   960   let us finish the termination proof:
       
   961   *}
       
   962 
       
   963   show "wf (measure (size o snd))" by simp
       
   964 next
       
   965   fix f l and x :: "'a tree"
       
   966   assume "x \<in> set l"
       
   967   thus "((f, x), (f, Branch l)) \<in> measure (size o snd)"
       
   968     apply simp
       
   969     txt {*
       
   970       Simplification returns the following subgoal: 
       
   971 
       
   972       @{subgoals[display,indent=0]} 
       
   973 
       
   974       We are lacking a property about the function @{const
       
   975       tree_list_size}, which was generated automatically at the
       
   976       definition of the @{text tree} type. We should go back and prove
       
   977       it, by induction.
       
   978       *}
       
   979     oops
       
   980 
       
   981   lemma tree_list_size[simp]: "x \<in> set l \<Longrightarrow> size x < Suc (tree_list_size l)"
       
   982     by (induct l) auto
       
   983 
       
   984   text {* 
       
   985     Now the whole termination proof is automatic:
       
   986     *}
       
   987 
       
   988   termination 
       
   989     by lexicographic_order
       
   990   
       
   991 
       
   992 subsection {* Congruence Rules *}
       
   993 
       
   994 text {*
       
   995   Let's come back to the question how Isabelle knows about @{const
       
   996   map}.
       
   997 
       
   998   The knowledge about map is encoded in so-called congruence rules,
       
   999   which are special theorems known to the \cmd{function} command. The
       
  1000   rule for map is
       
  1001 
       
  1002   @{thm[display] map_cong}
       
  1003 
       
  1004   You can read this in the following way: Two applications of @{const
       
  1005   map} are equal, if the list arguments are equal and the functions
       
  1006   coincide on the elements of the list. This means that for the value 
       
  1007   @{term "map f l"} we only have to know how @{term f} behaves on
       
  1008   @{term l}.
       
  1009 
       
  1010   Usually, one such congruence rule is
       
  1011   needed for each higher-order construct that is used when defining
       
  1012   new functions. In fact, even basic functions like @{const
       
  1013   If} and @{const Let} are handeled by this mechanism. The congruence
       
  1014   rule for @{const If} states that the @{text then} branch is only
       
  1015   relevant if the condition is true, and the @{text else} branch only if it
       
  1016   is false:
       
  1017 
       
  1018   @{thm[display] if_cong}
       
  1019   
       
  1020   Congruence rules can be added to the
       
  1021   function package by giving them the @{term fundef_cong} attribute.
       
  1022 
       
  1023   Isabelle comes with predefined congruence rules for most of the
       
  1024   definitions.
       
  1025   But if you define your own higher-order constructs, you will have to
       
  1026   come up with the congruence rules yourself, if you want to use your
       
  1027   functions in recursive definitions. Since the structure of
       
  1028   congruence rules is a little unintuitive, here are some exercises:
       
  1029 *}
       
  1030 (*<*)
       
  1031 fun mapeven :: "(nat \<Rightarrow> nat) \<Rightarrow> nat list \<Rightarrow> nat list"
       
  1032 where
       
  1033   "mapeven f [] = []"
       
  1034 | "mapeven f (x#xs) = (if x mod 2 = 0 then f x # mapeven f xs else x #
       
  1035   mapeven f xs)"
       
  1036 (*>*)
       
  1037 text {*
       
  1038 
       
  1039   \begin{exercise}
       
  1040     Find a suitable congruence rule for the following function which
       
  1041   maps only over the even numbers in a list:
       
  1042 
       
  1043   @{thm[display] mapeven.simps}
       
  1044   \end{exercise}
       
  1045   
       
  1046   \begin{exercise}
       
  1047   What happens if the congruence rule for @{const If} is
       
  1048   disabled by declaring @{text "if_cong[fundef_cong del]"}?
       
  1049   \end{exercise}
       
  1050 
       
  1051   Note that in some cases there is no \qt{best} congruence rule.
       
  1052   \fixme
       
  1053 
       
  1054 *}
       
  1055 
       
  1056 
       
  1057 
       
  1058 
       
  1059 
       
  1060 
       
  1061 
       
  1062 section {* Appendix: Predefined Congruence Rules *}
       
  1063 
       
  1064 (*<*)
       
  1065 syntax (Rule output)
       
  1066   "==>" :: "prop \<Rightarrow> prop \<Rightarrow> prop"
       
  1067   ("\<^raw:\mbox{}\inferrule{\mbox{>_\<^raw:}}>\<^raw:{\mbox{>_\<^raw:}}>")
       
  1068 
       
  1069   "_bigimpl" :: "asms \<Rightarrow> prop \<Rightarrow> prop"
       
  1070   ("\<^raw:\mbox{}\inferrule{>_\<^raw:}>\<^raw:{\mbox{>_\<^raw:}}>")
       
  1071 
       
  1072   "_asms" :: "prop \<Rightarrow> asms \<Rightarrow> asms" 
       
  1073   ("\<^raw:\mbox{>_\<^raw:}\\>/ _")
       
  1074 
       
  1075   "_asm" :: "prop \<Rightarrow> asms" ("\<^raw:\mbox{>_\<^raw:}>")
       
  1076 
       
  1077 definition 
       
  1078 FixImp :: "prop \<Rightarrow> prop \<Rightarrow> prop" 
       
  1079 where
       
  1080   "FixImp (PROP A) (PROP B) \<equiv> (PROP A \<Longrightarrow> PROP B)"
       
  1081 notation (output)
       
  1082   FixImp (infixr "\<Longrightarrow>" 1)
       
  1083 
       
  1084 setup {*
       
  1085 let
       
  1086   val fix_imps = map_aterms (fn Const ("==>", T) => Const ("Functions.FixImp", T) | t => t)
       
  1087   fun transform t = Logic.list_implies (map fix_imps (Logic.strip_imp_prems t), Logic.strip_imp_concl t)
       
  1088 in
       
  1089   TermStyle.add_style "topl" (K transform)
   477 end
  1090 end
       
  1091 *}
       
  1092 (*>*)
       
  1093 
       
  1094 subsection {* Basic Control Structures *}
       
  1095 
       
  1096 text {*
       
  1097 
       
  1098 @{thm_style[mode=Rule] topl if_cong}
       
  1099 
       
  1100 @{thm_style [mode=Rule] topl let_cong}
       
  1101 
       
  1102 *}
       
  1103 
       
  1104 subsection {* Data Types *}
       
  1105 
       
  1106 text {*
       
  1107 
       
  1108 For each \cmd{datatype} definition, a congruence rule for the case
       
  1109   combinator is registeres automatically. Here are the rules for
       
  1110   @{text "nat"} and @{text "list"}:
       
  1111 
       
  1112 \begin{center}@{thm_style[mode=Rule] topl nat.case_cong}\end{center}
       
  1113 
       
  1114 \begin{center}@{thm_style[mode=Rule] topl list.case_cong}\end{center}
       
  1115 
       
  1116 *}
       
  1117 
       
  1118 subsection {* List combinators *}
       
  1119 
       
  1120 
       
  1121 text {*
       
  1122 
       
  1123 @{thm_style[mode=Rule] topl map_cong}
       
  1124 
       
  1125 @{thm_style[mode=Rule] topl filter_cong}
       
  1126 
       
  1127 @{thm_style[mode=Rule] topl foldr_cong}
       
  1128 
       
  1129 @{thm_style[mode=Rule] topl foldl_cong}
       
  1130 
       
  1131 Similar: takewhile, dropwhile
       
  1132 
       
  1133 *}
       
  1134 
       
  1135 subsection {* Sets *}
       
  1136 
       
  1137 
       
  1138 text {*
       
  1139 
       
  1140 @{thm_style[mode=Rule] topl ball_cong}
       
  1141 
       
  1142 @{thm_style[mode=Rule] topl bex_cong}
       
  1143 
       
  1144 @{thm_style[mode=Rule] topl UN_cong}
       
  1145 
       
  1146 @{thm_style[mode=Rule] topl INT_cong}
       
  1147 
       
  1148 @{thm_style[mode=Rule] topl image_cong}
       
  1149 
       
  1150 
       
  1151 *}
       
  1152 
       
  1153 
       
  1154 
       
  1155 
       
  1156 
       
  1157 
       
  1158 end