doc-src/Functions/Thy/Functions.thy
changeset 41846 b368a7aee46a
parent 39754 150f831ce4a3
child 41847 b0d6acf73588
equal deleted inserted replaced
41845:6611b9cef38b 41846:b368a7aee46a
   700   However, the \cmd{function} package does support partiality to a
   700   However, the \cmd{function} package does support partiality to a
   701   certain extent. Let's look at the following function which looks
   701   certain extent. Let's look at the following function which looks
   702   for a zero of a given function f. 
   702   for a zero of a given function f. 
   703 *}
   703 *}
   704 
   704 
   705 function (*<*)(domintros, tailrec)(*>*)findzero :: "(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat"
   705 function (*<*)(domintros)(*>*)findzero :: "(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat"
   706 where
   706 where
   707   "findzero f n = (if f n = 0 then n else findzero f (Suc n))"
   707   "findzero f n = (if f n = 0 then n else findzero f (Suc n))"
   708 by pat_completeness auto
   708 by pat_completeness auto
   709 (*<*)declare findzero.simps[simp del](*>*)
   709 (*<*)declare findzero.simps[simp del](*>*)
   710 
   710 
   957   lemmas which are occasionally useful are @{text accpI}, @{text
   957   lemmas which are occasionally useful are @{text accpI}, @{text
   958   accp_downward}, and of course the introduction and elimination rules
   958   accp_downward}, and of course the introduction and elimination rules
   959   for the recursion relation @{text "findzero.intros"} and @{text "findzero.cases"}.
   959   for the recursion relation @{text "findzero.intros"} and @{text "findzero.cases"}.
   960 *}
   960 *}
   961 
   961 
   962 (*lemma findzero_nicer_domintros:
       
   963   "f x = 0 \<Longrightarrow> findzero_dom (f, x)"
       
   964   "findzero_dom (f, Suc x) \<Longrightarrow> findzero_dom (f, x)"
       
   965 by (rule accpI, erule findzero_rel.cases, auto)+
       
   966 *)
       
   967   
       
   968 subsection {* A Useful Special Case: Tail recursion *}
       
   969 
       
   970 text {*
       
   971   The domain predicate is our trick that allows us to model partiality
       
   972   in a world of total functions. The downside of this is that we have
       
   973   to carry it around all the time. The termination proof above allowed
       
   974   us to replace the abstract @{term "findzero_dom (f, n)"} by the more
       
   975   concrete @{term "(x \<ge> n \<and> f x = (0::nat))"}, but the condition is still
       
   976   there and can only be discharged for special cases.
       
   977   In particular, the domain predicate guards the unfolding of our
       
   978   function, since it is there as a condition in the @{text psimp}
       
   979   rules. 
       
   980 
       
   981   Now there is an important special case: We can actually get rid
       
   982   of the condition in the simplification rules, \emph{if the function
       
   983   is tail-recursive}. The reason is that for all tail-recursive
       
   984   equations there is a total function satisfying them, even if they
       
   985   are non-terminating. 
       
   986 
       
   987 %  A function is tail recursive, if each call to the function is either
       
   988 %  equal
       
   989 %
       
   990 %  So the outer form of the 
       
   991 %
       
   992 %if it can be written in the following
       
   993 %  form:
       
   994 %  {term[display] "f x = (if COND x then BASE x else f (LOOP x))"}
       
   995 
       
   996 
       
   997   The function package internally does the right construction and can
       
   998   derive the unconditional simp rules, if we ask it to do so. Luckily,
       
   999   our @{const "findzero"} function is tail-recursive, so we can just go
       
  1000   back and add another option to the \cmd{function} command:
       
  1001 
       
  1002 \vspace{1ex}
       
  1003 \noindent\cmd{function} @{text "(domintros, tailrec) findzero :: \"(nat \<Rightarrow> nat) \<Rightarrow> nat \<Rightarrow> nat\""}\\%
       
  1004 \cmd{where}\isanewline%
       
  1005 \ \ \ldots\\%
       
  1006 
       
  1007   
       
  1008   \noindent Now, we actually get unconditional simplification rules, even
       
  1009   though the function is partial:
       
  1010 *}
       
  1011 
       
  1012 thm findzero.simps
       
  1013 
       
  1014 text {*
       
  1015   @{thm[display] findzero.simps}
       
  1016 
       
  1017   \noindent Of course these would make the simplifier loop, so we better remove
       
  1018   them from the simpset:
       
  1019 *}
       
  1020 
       
  1021 declare findzero.simps[simp del]
       
  1022 
       
  1023 text {* 
       
  1024   Getting rid of the domain conditions in the simplification rules is
       
  1025   not only useful because it simplifies proofs. It is also required in
       
  1026   order to use Isabelle's code generator to generate ML code
       
  1027   from a function definition.
       
  1028   Since the code generator only works with equations, it cannot be
       
  1029   used with @{text "psimp"} rules. Thus, in order to generate code for
       
  1030   partial functions, they must be defined as a tail recursion.
       
  1031   Luckily, many functions have a relatively natural tail recursive
       
  1032   definition.
       
  1033 *}
       
  1034 
       
  1035 section {* Nested recursion *}
   962 section {* Nested recursion *}
  1036 
   963 
  1037 text {*
   964 text {*
  1038   Recursive calls which are nested in one another frequently cause
   965   Recursive calls which are nested in one another frequently cause
  1039   complications, since their termination proof can depend on a partial
   966   complications, since their termination proof can depend on a partial