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 |