src/Doc/Codegen/Partial_Functions.thy
changeset 76673 059a68d21f0f
parent 76650 a2c23c68f699
child 76987 4c275405faae
equal deleted inserted replaced
76660:89f78f76df1c 76673:059a68d21f0f
     1 theory Partial_Functions
     1 theory Partial_Functions
     2 imports Main "HOL-Library.Monad_Syntax"
     2 imports Setup "HOL-Library.Monad_Syntax"
     3 begin
     3 begin
     4 
     4 
     5 section \<open>Partial Functions \label{sec:partial}\<close>
     5 section \<open>Partial Functions \label{sec:partial}\<close>
     6 
     6 
     7 text \<open>We demonstrate three approaches to defining executable partial recursive functions.
     7 text \<open>We demonstrate three approaches to defining executable partial recursive functions,
       
     8 i.e.\ functions that do not terminate for all inputs.
     8 The main points are the definitions of the functions and the inductive proofs about them.
     9 The main points are the definitions of the functions and the inductive proofs about them.
     9 
    10 
    10 Our concrete example represents a typical termination problem: following a data structure that
    11 Our concrete example represents a typical termination problem: following a data structure that
    11 may contain cycles. We want to follow a mapping from \<open>nat\<close> to \<open>nat\<close> to the end
    12 may contain cycles. We want to follow a mapping from \<open>nat\<close> to \<open>nat\<close> to the end
    12 (until we leave its domain). The mapping is represented by a list \<open>ns :: nat list\<close>
    13 (until we leave its domain). The mapping is represented by a list \<open>ns :: nat list\<close>
    21 "rel ns = set(zip ns [0..<length ns])"
    22 "rel ns = set(zip ns [0..<length ns])"
    22 
    23 
    23 lemma finite_rel[simp]: "finite(rel ns)"
    24 lemma finite_rel[simp]: "finite(rel ns)"
    24 (*<*)by(simp add: rel_def)(*>*)
    25 (*<*)by(simp add: rel_def)(*>*)
    25 
    26 
    26 text \<open>This relation should be acyclic
    27 text \<open>\noindent This relation should be acyclic
    27  to guarantee termination of the partial functions defined below.\<close>
    28  to guarantee termination of the partial functions defined below.\<close>
    28 
    29 
    29 
    30 
    30 subsection \<open>Tail recursion\<close>
    31 subsection \<open>Tail recursion\<close>
    31 
    32 
    81 
    82 
    82 partial_function (option) count :: "nat list \<Rightarrow> nat \<Rightarrow> nat option" where
    83 partial_function (option) count :: "nat list \<Rightarrow> nat \<Rightarrow> nat option" where
    83 "count ns n
    84 "count ns n
    84 = (if n < length ns then do {k \<leftarrow> count ns (ns!n); Some (k+1)} else Some 0)"
    85 = (if n < length ns then do {k \<leftarrow> count ns (ns!n); Some (k+1)} else Some 0)"
    85 
    86 
    86 text \<open>We use a Haskell-like \<open>do\<close> notation (import @{theory "HOL-Library.Monad_Syntax"})
    87 text \<open>\noindent We use a Haskell-like \<open>do\<close> notation (import @{theory "HOL-Library.Monad_Syntax"})
    87 to abbreviate the clumsy explicit
    88 to abbreviate the clumsy explicit
    88 
    89 
    89 \noindent
    90 \noindent
    90 @{term "case count ns (ns!n) of Some k \<Rightarrow> Some(k+1) | None \<Rightarrow> None"}.
    91 @{term "case count ns (ns!n) of Some k \<Rightarrow> Some(k+1) | None \<Rightarrow> None"}.
    91 
    92 
   121 
   122 
   122 typedef acyc = "{ns. acyclic(rel ns)}"
   123 typedef acyc = "{ns. acyclic(rel ns)}"
   123 morphisms rep_acyc abs_acyc
   124 morphisms rep_acyc abs_acyc
   124 using acyclic_rel_Nil by auto
   125 using acyclic_rel_Nil by auto
   125 
   126 
   126 text \<open>This defines two functions \<open>rep_acyc :: acyc \<Rightarrow> nat list\<close> and \<open>abs_acyc :: nat list \<Rightarrow> acyc\<close>.
   127 text \<open>\noindent This defines two functions @{term [source] "rep_acyc :: acyc \<Rightarrow> nat list"}
   127 Function @{const abs_acyc} is only defined on acyclic lists and not executable for that reason.\<close>
   128 and @{const abs_acyc} \<open>::\<close> \mbox{@{typ "nat list \<Rightarrow> acyc"}}.
       
   129 Function @{const abs_acyc} is only defined on acyclic lists and not executable for that reason.
       
   130 Type \<open>dlist\<close> in Section~\ref{sec:partiality} is defined in the same manner.
       
   131 
       
   132 The following command sets up infrastructure for lifting functions on @{typ "nat list"}
       
   133 to @{typ acyc} (used by @{command_def lift_definition} below) \cite{isabelle-isar-ref}.\<close>
   128 
   134 
   129 setup_lifting type_definition_acyc
   135 setup_lifting type_definition_acyc
   130 
   136 
   131 text \<open>This is how @{const follow} can be defined on @{typ acyc}:\<close>
   137 text \<open>This is how @{const follow} can be defined on @{typ acyc}:\<close>
   132 
   138 
   133 function follow2 :: "acyc \<Rightarrow> nat \<Rightarrow> nat" where
   139 function follow2 :: "acyc \<Rightarrow> nat \<Rightarrow> nat" where
   134 "follow2 ac n
   140 "follow2 ac n
   135 = (let ns = rep_acyc ac in if n < length ns then follow2 ac (ns!n) else n)"
   141 = (let ns = rep_acyc ac in if n < length ns then follow2 ac (ns!n) else n)"
   136 by pat_completeness auto
   142 by pat_completeness auto
   137 
   143 
   138 text \<open>Now we prepare for termination proof.
   144 text \<open>Now we prepare for the termination proof.
   139  Relation \<open>rel_follow2\<close> is almost identical to @{const rel_follow}.\<close>
   145  Relation \<open>rel_follow2\<close> is almost identical to @{const rel_follow}.\<close>
   140 
   146 
   141 definition "rel_follow2 = same_fst (acyclic o rel o rep_acyc) (rel o rep_acyc)"
   147 definition "rel_follow2 = same_fst (acyclic o rel o rep_acyc) (rel o rep_acyc)"
   142 
   148 
   143 lemma wf_follow2: "wf rel_follow2"
   149 lemma wf_follow2: "wf rel_follow2"
   186 
   192 
   187 lift_definition is_acyc :: "nat list \<Rightarrow> acyc" is 
   193 lift_definition is_acyc :: "nat list \<Rightarrow> acyc" is 
   188   "\<lambda>ns. if acyclic(rel ns) then ns else []"
   194   "\<lambda>ns. if acyclic(rel ns) then ns else []"
   189 (*<*)by (auto simp: acyclic_rel_Nil)(*>*)
   195 (*<*)by (auto simp: acyclic_rel_Nil)(*>*)
   190 
   196 
   191 text \<open>This works because we can easily prove that for any \<open>ns\<close>,
   197 text \<open>\noindent This works because we can easily prove that for any \<open>ns\<close>,
   192  the \<open>\<lambda>\<close>-term produces an acyclic list.
   198  the \<open>\<lambda>\<close>-term produces an acyclic list.
   193 But it requires the possibly expensive check @{prop "acyclic(rel ns)"}.\<close>
   199 But it requires the possibly expensive check @{prop "acyclic(rel ns)"}.\<close>
   194 
   200 
   195 definition "follow_test ns n = follow2 (is_acyc ns) n"
   201 definition "follow_test ns n = follow2 (is_acyc ns) n"
   196 
   202