4 Throughout the tutorial we have emphasized the fact that all functions |
4 Throughout the tutorial we have emphasized the fact that all functions |
5 in HOL are total. Hence we cannot hope to define truly partial |
5 in HOL are total. Hence we cannot hope to define truly partial |
6 functions. The best we can do are functions that are |
6 functions. The best we can do are functions that are |
7 \emph{underdefined}\index{underdefined function}: |
7 \emph{underdefined}\index{underdefined function}: |
8 for certain arguments we only know that a result |
8 for certain arguments we only know that a result |
9 exists, but we don't know what it is. When defining functions that are |
9 exists, but we do not know what it is. When defining functions that are |
10 normally considered partial, underdefinedness turns out to be a very |
10 normally considered partial, underdefinedness turns out to be a very |
11 reasonable alternative. |
11 reasonable alternative. |
12 |
12 |
13 We have already seen an instance of underdefinedness by means of |
13 We have already seen an instance of underdefinedness by means of |
14 non-exhaustive pattern matching: the definition of @{term last} in |
14 non-exhaustive pattern matching: the definition of @{term last} in |
18 consts hd :: "'a list \<Rightarrow> 'a" |
18 consts hd :: "'a list \<Rightarrow> 'a" |
19 primrec "hd (x#xs) = x" |
19 primrec "hd (x#xs) = x" |
20 |
20 |
21 text{*\noindent |
21 text{*\noindent |
22 although it generates a warning. |
22 although it generates a warning. |
23 |
|
24 Even ordinary definitions allow underdefinedness, this time by means of |
23 Even ordinary definitions allow underdefinedness, this time by means of |
25 preconditions: |
24 preconditions: |
26 *} |
25 *} |
27 |
26 |
28 constdefs minus :: "nat \<Rightarrow> nat \<Rightarrow> nat" |
27 constdefs minus :: "nat \<Rightarrow> nat \<Rightarrow> nat" |
62 standard mathematical division function. |
61 standard mathematical division function. |
63 |
62 |
64 As a more substantial example we consider the problem of searching a graph. |
63 As a more substantial example we consider the problem of searching a graph. |
65 For simplicity our graph is given by a function (@{term f}) of |
64 For simplicity our graph is given by a function (@{term f}) of |
66 type @{typ"'a \<Rightarrow> 'a"} which |
65 type @{typ"'a \<Rightarrow> 'a"} which |
67 maps each node to its successor, and the task is to find the end of a chain, |
66 maps each node to its successor, i.e.\ the graph is really a tree. |
68 i.e.\ a node pointing to itself. Here is a first attempt: |
67 The task is to find the end of a chain, modelled by a node pointing to |
|
68 itself. Here is a first attempt: |
69 @{prop[display]"find(f,x) = (if f x = x then x else find(f, f x))"} |
69 @{prop[display]"find(f,x) = (if f x = x then x else find(f, f x))"} |
70 This may be viewed as a fixed point finder or as one half of the well known |
70 This may be viewed as a fixed point finder or as one half of the well known |
71 \emph{Union-Find} algorithm. |
71 \emph{Union-Find} algorithm. |
72 The snag is that it may not terminate if @{term f} has non-trivial cycles. |
72 The snag is that it may not terminate if @{term f} has non-trivial cycles. |
73 Phrased differently, the relation |
73 Phrased differently, the relation |
89 |
89 |
90 text{*\noindent |
90 text{*\noindent |
91 The recursion equation itself should be clear enough: it is our aborted |
91 The recursion equation itself should be clear enough: it is our aborted |
92 first attempt augmented with a check that there are no non-trivial loops. |
92 first attempt augmented with a check that there are no non-trivial loops. |
93 |
93 |
94 What complicates the termination proof is that the argument of |
94 What complicates the termination proof is that the argument of @{term find} |
95 @{term find} is a pair. To express the required well-founded relation |
95 is a pair. To express the required well-founded relation we employ the |
96 we employ the predefined combinator @{term same_fst} of type |
96 predefined combinator @{term same_fst} of type |
97 @{text[display]"('a \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b\<times>'b)set) \<Rightarrow> (('a\<times>'b) \<times> ('a\<times>'b))set"} |
97 @{text[display]"('a \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b\<times>'b)set) \<Rightarrow> (('a\<times>'b) \<times> ('a\<times>'b))set"} |
98 defined as |
98 defined as |
99 @{thm[display]same_fst_def[no_vars]} |
99 @{thm[display]same_fst_def[no_vars]} |
100 This combinator is designed for recursive functions on pairs where the first |
100 This combinator is designed for |
101 component of the argument is passed unchanged to all recursive |
101 recursive functions on pairs where the first component of the argument is |
102 calls. Given a constraint on the first component and a relation on the second |
102 passed unchanged to all recursive calls. Given a constraint on the first |
103 component, @{term same_fst} builds the required relation on pairs. |
103 component and a relation on the second component, @{term same_fst} builds the |
104 The theorem @{thm[display]wf_same_fst[no_vars]} |
104 required relation on pairs. The theorem |
105 is known to the well-foundedness prover of \isacommand{recdef}. |
105 @{thm[display]wf_same_fst[no_vars]} |
106 Thus well-foundedness of the given relation is immediate. |
106 is known to the well-foundedness prover of \isacommand{recdef}. Thus |
107 Furthermore, each recursive call descends along the given relation: |
107 well-foundedness of the relation given to \isacommand{recdef} is immediate. |
108 the first argument stays unchanged and the second one descends along |
108 Furthermore, each recursive call descends along that relation: the first |
109 @{term"step1 f"}. The proof merely requires unfolding of some definitions. |
109 argument stays unchanged and the second one descends along @{term"step1 |
|
110 f"}. The proof merely requires unfolding of some definitions, as specified in |
|
111 the \isacommand{hints} above. |
110 |
112 |
111 Normally you will then derive the following conditional variant of and from |
113 Normally you will then derive the following conditional variant of and from |
112 the recursion equation |
114 the recursion equation |
113 *} |
115 *} |
114 |
116 |
202 @{term while} at all? The only reason is executability: the recursion |
204 @{term while} at all? The only reason is executability: the recursion |
203 equation for @{term while} is a directly executable functional |
205 equation for @{term while} is a directly executable functional |
204 program. This is in stark contrast to guarded recursion as introduced |
206 program. This is in stark contrast to guarded recursion as introduced |
205 above which requires an explicit test @{prop"x \<in> dom f"} in the |
207 above which requires an explicit test @{prop"x \<in> dom f"} in the |
206 function body. Unless @{term dom} is trivial, this leads to a |
208 function body. Unless @{term dom} is trivial, this leads to a |
207 definition that is impossible to execute (or prohibitively slow). |
209 definition that is impossible to execute or prohibitively slow. |
208 Thus, if you are aiming for an efficiently executable definition |
210 Thus, if you are aiming for an efficiently executable definition |
209 of a partial function, you are likely to need @{term while}. |
211 of a partial function, you are likely to need @{term while}. |
210 *} |
212 *} |
211 |
213 |
212 (*<*)end(*>*) |
214 (*<*)end(*>*) |