fun add where "add 0 y = y"
| "add (Suc x) y = Suc (add x y)"
thm add.simps thm add.induct \<comment> \<open>Note the curried induction predicate\<close>
subsection \<open>Nested recursion\<close>
function nz where "nz 0 = 0"
| "nz (Suc x) = nz (nz x)" by pat_completeness auto
lemma nz_is_zero: \<comment> \<open>A lemma we need to prove termination\<close> assumes trm: "nz_dom x" shows"nz x = 0" using trm by induct (auto simp: nz.psimps)
termination nz by (relation "less_than") (auto simp:nz_is_zero)
thm nz.simps thm nz.induct
subsubsection \<open>Here comes McCarthy's 91-function\<close>
function f91 :: "nat \ nat" where "f91 n = (if 100 < n then n - 10 else f91 (f91 (n + 11)))" by pat_completeness auto
text\<open>Prove a lemma before attempting a termination proof:\<close> lemma f91_estimate: assumes trm: "f91_dom n" shows"n < f91 n + 11" using trm by induct (auto simp: f91.psimps)
fix n :: nat assume"\ 100 < n" \ \Inner call\ thenshow"(n + 11, n) \ ?R" by simp
assume inner_trm: "f91_dom (n + 11)"\<comment> \<open>Outer call\<close> with f91_estimate have"n + 11 < f91 (n + 11) + 11" . with\<open>\<not> 100 < n\<close> show "(f91 (n + 11), n) \<in> ?R" by simp qed
text\<open>Now trivial (even though it does not belong here):\<close> lemma"f91 n = (if 100 < n then n - 10 else 91)" by (induct n rule: f91.induct) auto
subsubsection \<open>Here comes Takeuchi's function\<close>
definition tak_m1 where"tak_m1 = (\(x,y,z). if x \ y then 0 else 1)" definition tak_m2 where"tak_m2 = (\(x,y,z). nat (Max {x, y, z} - Min {x, y, z}))" definition tak_m3 where"tak_m3 = (\(x,y,z). nat (x - Min {x, y, z}))"
function tak :: "int \ int \ int \ int" where "tak x y z = (if x \ y then y else tak (tak (x-1) y z) (tak (y-1) z x) (tak (z-1) x y))" by auto
lemma tak_pcorrect: "tak_dom (x, y, z) \ tak x y z = (if x \ y then y else if y \ z then z else x)" by (induction x y z rule: tak.pinduct) (auto simp: tak.psimps)
theorem tak_correct: "tak x y z = (if x \ y then y else if y \ z then z else x)" by (induction x y z rule: tak.induct) auto
subsection \<open>More general patterns\<close>
subsubsection \<open>Overlapping patterns\<close>
text\<open>
Currently, patterns must always be compatible with each other, since
no automatic splitting takes place. But the following definition of
GCD is OK, although patterns overlap: \<close>
fun gcd2 :: "nat \ nat \ nat" where "gcd2 x 0 = x"
| "gcd2 0 y = y"
| "gcd2 (Suc x) (Suc y) = (if x < y then gcd2 (Suc x) (y - x)
else gcd2 (x - y) (Suc y))"
thm gcd2.simps thm gcd2.induct
subsubsection \<open>Guards\<close>
text\<open>We can reformulate the above example using guarded patterns:\<close>
text\<open>General patterns allow even strange definitions:\<close>
function ev :: "nat \ bool" where "ev (2 * n) = True"
| "ev (2 * n + 1) = False" proof - \<comment> \<open>completeness is more difficult here \dots\<close> fix P :: bool fix x :: nat assume c1: "\n. x = 2 * n \ P" and c2: "\n. x = 2 * n + 1 \ P" have divmod: "x = 2 * (x div 2) + (x mod 2)"by auto show P proof (cases "x mod 2 = 0") case True with divmod have"x = 2 * (x div 2)"by simp with c1 show"P" . next case False thenhave"x mod 2 = 1"by simp with divmod have"x = 2 * (x div 2) + 1"by simp with c2 show"P" . qed qed presburger+ \<comment> \<open>solve compatibility with presburger\<close> terminationby lexicographic_order
thm ev.simps thm ev.induct thm ev.cases
subsection \<open>Mutual Recursion\<close>
fun evn od :: "nat \ bool" where "evn 0 = True"
| "od 0 = False"
| "evn (Suc n) = od n"
| "od (Suc n) = evn n"
thm evn.simps thm od.simps
thm evn_od.induct thm evn_od.termination
thm evn.elims thm od.elims
subsection \<open>Definitions in local contexts\<close>
locale my_monoid = fixes opr :: "'a \ 'a \ 'a" and un :: "'a" assumes assoc: "opr (opr x y) z = opr x (opr y z)" and lunit: "opr un x = x" and runit: "opr x un = x" begin
fun foldR :: "'a list \ 'a" where "foldR [] = un"
| "foldR (x # xs) = opr x (foldR xs)"
fun foldL :: "'a list \ 'a" where "foldL [] = un"
| "foldL [x] = x"
| "foldL (x # y # ys) = foldL (opr x y # ys)"
text\<open>If the predecessor of a number is 0, that number must be 0 or 1.\<close>
fun_cases pred0E[elim]: "pred n = 0"
lemma"pred n = 0 \ n = 0 \ n = Suc 0" by (erule pred0E) metis+
text\<open>
Other expressions on the right-hand side also work, but whether the
generated rule is useful depends on how well the simplifier can
simplify it. This example works well: \<close>
fun_cases pred42E[elim]: "pred n = 42"
lemma"pred n = 42 \ n = 43" by (erule pred42E)
subsubsection \<open>List to option\<close>
fun list_to_option :: "'a list \ 'a option" where "list_to_option [x] = Some x"
| "list_to_option _ = None"
fun_cases list_to_option_NoneE: "list_to_option xs = None" and list_to_option_SomeE: "list_to_option xs = Some x"
lemma"list_to_option xs = Some y \ xs = [y]" by (erule list_to_option_SomeE)
text\<open> \<open>fun_cases\<close> does not only recognise function equations, but also works with
functions that return a boolean, e.g.: \<close>
fun_cases xor_TrueE: "xor a b"and xor_FalseE: "\xor a b" print_theorems
subsubsection \<open>Many parameters\<close>
fun sum4 :: "nat \ nat \ nat \ nat \ nat" where"sum4 a b c d = a + b + c + d"
fun_cases sum40E: "sum4 a b c d = 0"
lemma"sum4 a b c d = 0 \ a = 0" by (erule sum40E)
subsection \<open>Partial Function Definitions\<close>
text\<open>Partial functions in the option monad:\<close>
partial_function (option)
collatz :: "nat \ nat list option" where "collatz n =
(if n \<le> 1 then Some [n]
else if even n then do { ns \<leftarrow> collatz (n div 2); Some (n # ns) }
else do { ns \<leftarrow> collatz (3 * n + 1); Some (n # ns)})"
declare collatz.simps[code] value"collatz 23"
text\<open>Tail-recursive functions:\<close>
partial_function (tailrec) fixpoint :: "('a \ 'a) \ 'a \ 'a" where "fixpoint f x = (if f x = x then x else fixpoint f (f x))"
subsection \<open>Regression tests\<close>
text\<open>
The following examples mainly serve as tests for the function package. \<close>
fun listlen :: "'a list \ nat" where "listlen [] = 0"
| "listlen (x#xs) = Suc (listlen xs)"
subsubsection \<open>Context recursion\<close>
fun f :: "nat \ nat" where
zero: "f 0 = 0"
| succ: "f (Suc n) = (if f n = 0 then 0 else f n)"
subsubsection \<open>A combination of context and nested recursion\<close>
function h :: "nat \ nat" where "h 0 = 0"
| "h (Suc n) = (if h n = 0 then h (h n) else h n)" by pat_completeness auto
subsubsection \<open>Context, but no recursive call\<close>
fun i :: "nat \ nat" where "i 0 = 0"
| "i (Suc n) = (if n = 0 then 0 else i n)"
fun fa :: "nat \ nat \ nat" where "fa 0 y = 0"
| "fa (Suc n) y = (if fa n y = 0 then 0 else fa n y)"
subsubsection \<open>Let\<close>
fun j :: "nat \ nat" where "j 0 = 0"
| "j (Suc n) = (let u = n in Suc (j u))"
text\<open>There were some problems with fresh names \dots\<close> function k :: "nat \ nat" where "k x = (let a = x; b = x in k x)" by pat_completeness auto
function f2 :: "(nat \ nat) \ (nat \ nat)" where "f2 p = (let (x,y) = p in f2 (y,x))" by pat_completeness auto
fun treemap :: "('a \ 'a) \ 'a tree \ 'a tree" where "treemap fn (Leaf n) = (Leaf (fn n))"
| "treemap fn (Branch l) = (Branch (map (treemap fn) l))"
fun tinc :: "nat tree \ nat tree" where "tinc (Leaf n) = Leaf (Suc n)"
| "tinc (Branch l) = Branch (map tinc l)"
fun testcase :: "'a tree \ 'a list" where "testcase (Leaf a) = [a]"
| "testcase (Branch x) =
(let xs = concat (map testcase x);
ys = concat (map testcase x) in
xs @ ys)"
subsubsection \<open>Pattern matching on records\<close>
record point =
Xcoord :: int
Ycoord :: int
function swp :: "point \ point" where "swp \ Xcoord = x, Ycoord = y \ = \ Xcoord = y, Ycoord = x \" proof - fix P x assume"\xa y. x = \Xcoord = xa, Ycoord = y\ \ P" thenshow P by (cases x) qed auto terminationby rule auto
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.