1 (*<*) |
1 (*<*) |
2 theory fun0 imports Main begin |
2 theory fun0 imports Main begin |
3 (*>*) |
3 (*>*) |
4 |
4 |
5 text{* |
5 text\<open> |
6 \subsection{Definition} |
6 \subsection{Definition} |
7 \label{sec:fun-examples} |
7 \label{sec:fun-examples} |
8 |
8 |
9 Here is a simple example, the \rmindex{Fibonacci function}: |
9 Here is a simple example, the \rmindex{Fibonacci function}: |
10 *} |
10 \<close> |
11 |
11 |
12 fun fib :: "nat \<Rightarrow> nat" where |
12 fun fib :: "nat \<Rightarrow> nat" where |
13 "fib 0 = 0" | |
13 "fib 0 = 0" | |
14 "fib (Suc 0) = 1" | |
14 "fib (Suc 0) = 1" | |
15 "fib (Suc(Suc x)) = fib x + fib (Suc x)" |
15 "fib (Suc(Suc x)) = fib x + fib (Suc x)" |
16 |
16 |
17 text{*\noindent |
17 text\<open>\noindent |
18 This resembles ordinary functional programming languages. Note the obligatory |
18 This resembles ordinary functional programming languages. Note the obligatory |
19 \isacommand{where} and \isa{|}. Command \isacommand{fun} declares and |
19 \isacommand{where} and \isa{|}. Command \isacommand{fun} declares and |
20 defines the function in one go. Isabelle establishes termination automatically |
20 defines the function in one go. Isabelle establishes termination automatically |
21 because @{const fib}'s argument decreases in every recursive call. |
21 because @{const fib}'s argument decreases in every recursive call. |
22 |
22 |
23 Slightly more interesting is the insertion of a fixed element |
23 Slightly more interesting is the insertion of a fixed element |
24 between any two elements of a list: |
24 between any two elements of a list: |
25 *} |
25 \<close> |
26 |
26 |
27 fun sep :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where |
27 fun sep :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where |
28 "sep a [] = []" | |
28 "sep a [] = []" | |
29 "sep a [x] = [x]" | |
29 "sep a [x] = [x]" | |
30 "sep a (x#y#zs) = x # a # sep a (y#zs)" |
30 "sep a (x#y#zs) = x # a # sep a (y#zs)" |
31 |
31 |
32 text{*\noindent |
32 text\<open>\noindent |
33 This time the length of the list decreases with the |
33 This time the length of the list decreases with the |
34 recursive call; the first argument is irrelevant for termination. |
34 recursive call; the first argument is irrelevant for termination. |
35 |
35 |
36 Pattern matching\index{pattern matching!and \isacommand{fun}} |
36 Pattern matching\index{pattern matching!and \isacommand{fun}} |
37 need not be exhaustive and may employ wildcards: |
37 need not be exhaustive and may employ wildcards: |
38 *} |
38 \<close> |
39 |
39 |
40 fun last :: "'a list \<Rightarrow> 'a" where |
40 fun last :: "'a list \<Rightarrow> 'a" where |
41 "last [x] = x" | |
41 "last [x] = x" | |
42 "last (_#y#zs) = last (y#zs)" |
42 "last (_#y#zs) = last (y#zs)" |
43 |
43 |
44 text{* |
44 text\<open> |
45 Overlapping patterns are disambiguated by taking the order of equations into |
45 Overlapping patterns are disambiguated by taking the order of equations into |
46 account, just as in functional programming: |
46 account, just as in functional programming: |
47 *} |
47 \<close> |
48 |
48 |
49 fun sep1 :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where |
49 fun sep1 :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where |
50 "sep1 a (x#y#zs) = x # a # sep1 a (y#zs)" | |
50 "sep1 a (x#y#zs) = x # a # sep1 a (y#zs)" | |
51 "sep1 _ xs = xs" |
51 "sep1 _ xs = xs" |
52 |
52 |
53 text{*\noindent |
53 text\<open>\noindent |
54 To guarantee that the second equation can only be applied if the first |
54 To guarantee that the second equation can only be applied if the first |
55 one does not match, Isabelle internally replaces the second equation |
55 one does not match, Isabelle internally replaces the second equation |
56 by the two possibilities that are left: @{prop"sep1 a [] = []"} and |
56 by the two possibilities that are left: @{prop"sep1 a [] = []"} and |
57 @{prop"sep1 a [x] = [x]"}. Thus the functions @{const sep} and |
57 @{prop"sep1 a [x] = [x]"}. Thus the functions @{const sep} and |
58 @{const sep1} are identical. |
58 @{const sep1} are identical. |
59 |
59 |
60 Because of its pattern matching syntax, \isacommand{fun} is also useful |
60 Because of its pattern matching syntax, \isacommand{fun} is also useful |
61 for the definition of non-recursive functions: |
61 for the definition of non-recursive functions: |
62 *} |
62 \<close> |
63 |
63 |
64 fun swap12 :: "'a list \<Rightarrow> 'a list" where |
64 fun swap12 :: "'a list \<Rightarrow> 'a list" where |
65 "swap12 (x#y#zs) = y#x#zs" | |
65 "swap12 (x#y#zs) = y#x#zs" | |
66 "swap12 zs = zs" |
66 "swap12 zs = zs" |
67 |
67 |
68 text{* |
68 text\<open> |
69 After a function~$f$ has been defined via \isacommand{fun}, |
69 After a function~$f$ has been defined via \isacommand{fun}, |
70 its defining equations (or variants derived from them) are available |
70 its defining equations (or variants derived from them) are available |
71 under the name $f$@{text".simps"} as theorems. |
71 under the name $f$@{text".simps"} as theorems. |
72 For example, look (via \isacommand{thm}) at |
72 For example, look (via \isacommand{thm}) at |
73 @{thm[source]sep.simps} and @{thm[source]sep1.simps} to see that they define |
73 @{thm[source]sep.simps} and @{thm[source]sep1.simps} to see that they define |
85 recursive call. |
85 recursive call. |
86 |
86 |
87 More generally, \isacommand{fun} allows any \emph{lexicographic |
87 More generally, \isacommand{fun} allows any \emph{lexicographic |
88 combination} of size measures in case there are multiple |
88 combination} of size measures in case there are multiple |
89 arguments. For example, the following version of \rmindex{Ackermann's |
89 arguments. For example, the following version of \rmindex{Ackermann's |
90 function} is accepted: *} |
90 function} is accepted:\<close> |
91 |
91 |
92 fun ack2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
92 fun ack2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
93 "ack2 n 0 = Suc n" | |
93 "ack2 n 0 = Suc n" | |
94 "ack2 0 (Suc m) = ack2 (Suc 0) m" | |
94 "ack2 0 (Suc m) = ack2 (Suc 0) m" | |
95 "ack2 (Suc n) (Suc m) = ack2 (ack2 n (Suc m)) m" |
95 "ack2 (Suc n) (Suc m) = ack2 (ack2 n (Suc m)) m" |
96 |
96 |
97 text{* The order of arguments has no influence on whether |
97 text\<open>The order of arguments has no influence on whether |
98 \isacommand{fun} can prove termination of a function. For more details |
98 \isacommand{fun} can prove termination of a function. For more details |
99 see elsewhere~@{cite bulwahnKN07}. |
99 see elsewhere~@{cite bulwahnKN07}. |
100 |
100 |
101 \subsection{Simplification} |
101 \subsection{Simplification} |
102 \label{sec:fun-simplification} |
102 \label{sec:fun-simplification} |
106 In most cases this works fine, but there is a subtle |
106 In most cases this works fine, but there is a subtle |
107 problem that must be mentioned: simplification may not |
107 problem that must be mentioned: simplification may not |
108 terminate because of automatic splitting of @{text "if"}. |
108 terminate because of automatic splitting of @{text "if"}. |
109 \index{*if expressions!splitting of} |
109 \index{*if expressions!splitting of} |
110 Let us look at an example: |
110 Let us look at an example: |
111 *} |
111 \<close> |
112 |
112 |
113 fun gcd :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
113 fun gcd :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
114 "gcd m n = (if n=0 then m else gcd n (m mod n))" |
114 "gcd m n = (if n=0 then m else gcd n (m mod n))" |
115 |
115 |
116 text{*\noindent |
116 text\<open>\noindent |
117 The second argument decreases with each recursive call. |
117 The second argument decreases with each recursive call. |
118 The termination condition |
118 The termination condition |
119 @{prop[display]"n ~= (0::nat) ==> m mod n < n"} |
119 @{prop[display]"n ~= (0::nat) ==> m mod n < n"} |
120 is proved automatically because it is already present as a lemma in |
120 is proved automatically because it is already present as a lemma in |
121 HOL\@. Thus the recursion equation becomes a simplification |
121 HOL\@. Thus the recursion equation becomes a simplification |
143 @{text "if"} is involved. |
143 @{text "if"} is involved. |
144 |
144 |
145 If possible, the definition should be given by pattern matching on the left |
145 If possible, the definition should be given by pattern matching on the left |
146 rather than @{text "if"} on the right. In the case of @{term gcd} the |
146 rather than @{text "if"} on the right. In the case of @{term gcd} the |
147 following alternative definition suggests itself: |
147 following alternative definition suggests itself: |
148 *} |
148 \<close> |
149 |
149 |
150 fun gcd1 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
150 fun gcd1 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
151 "gcd1 m 0 = m" | |
151 "gcd1 m 0 = m" | |
152 "gcd1 m n = gcd1 n (m mod n)" |
152 "gcd1 m n = gcd1 n (m mod n)" |
153 |
153 |
154 text{*\noindent |
154 text\<open>\noindent |
155 The order of equations is important: it hides the side condition |
155 The order of equations is important: it hides the side condition |
156 @{prop"n ~= (0::nat)"}. Unfortunately, not all conditionals can be |
156 @{prop"n ~= (0::nat)"}. Unfortunately, not all conditionals can be |
157 expressed by pattern matching. |
157 expressed by pattern matching. |
158 |
158 |
159 A simple alternative is to replace @{text "if"} by @{text case}, |
159 A simple alternative is to replace @{text "if"} by @{text case}, |
160 which is also available for @{typ bool} and is not split automatically: |
160 which is also available for @{typ bool} and is not split automatically: |
161 *} |
161 \<close> |
162 |
162 |
163 fun gcd2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
163 fun gcd2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where |
164 "gcd2 m n = (case n=0 of True \<Rightarrow> m | False \<Rightarrow> gcd2 n (m mod n))" |
164 "gcd2 m n = (case n=0 of True \<Rightarrow> m | False \<Rightarrow> gcd2 n (m mod n))" |
165 |
165 |
166 text{*\noindent |
166 text\<open>\noindent |
167 This is probably the neatest solution next to pattern matching, and it is |
167 This is probably the neatest solution next to pattern matching, and it is |
168 always available. |
168 always available. |
169 |
169 |
170 A final alternative is to replace the offending simplification rules by |
170 A final alternative is to replace the offending simplification rules by |
171 derived conditional ones. For @{term gcd} it means we have to prove |
171 derived conditional ones. For @{term gcd} it means we have to prove |
172 these lemmas: |
172 these lemmas: |
173 *} |
173 \<close> |
174 |
174 |
175 lemma [simp]: "gcd m 0 = m" |
175 lemma [simp]: "gcd m 0 = m" |
176 apply(simp) |
176 apply(simp) |
177 done |
177 done |
178 |
178 |
179 lemma [simp]: "n \<noteq> 0 \<Longrightarrow> gcd m n = gcd n (m mod n)" |
179 lemma [simp]: "n \<noteq> 0 \<Longrightarrow> gcd m n = gcd n (m mod n)" |
180 apply(simp) |
180 apply(simp) |
181 done |
181 done |
182 |
182 |
183 text{*\noindent |
183 text\<open>\noindent |
184 Simplification terminates for these proofs because the condition of the @{text |
184 Simplification terminates for these proofs because the condition of the @{text |
185 "if"} simplifies to @{term True} or @{term False}. |
185 "if"} simplifies to @{term True} or @{term False}. |
186 Now we can disable the original simplification rule: |
186 Now we can disable the original simplification rule: |
187 *} |
187 \<close> |
188 |
188 |
189 declare gcd.simps [simp del] |
189 declare gcd.simps [simp del] |
190 |
190 |
191 text{* |
191 text\<open> |
192 \index{induction!recursion|(} |
192 \index{induction!recursion|(} |
193 \index{recursion induction|(} |
193 \index{recursion induction|(} |
194 |
194 |
195 \subsection{Induction} |
195 \subsection{Induction} |
196 \label{sec:fun-induction} |
196 \label{sec:fun-induction} |
205 \textbf{recursion induction}. Roughly speaking, it |
205 \textbf{recursion induction}. Roughly speaking, it |
206 requires you to prove for each \isacommand{fun} equation that the property |
206 requires you to prove for each \isacommand{fun} equation that the property |
207 you are trying to establish holds for the left-hand side provided it holds |
207 you are trying to establish holds for the left-hand side provided it holds |
208 for all recursive calls on the right-hand side. Here is a simple example |
208 for all recursive calls on the right-hand side. Here is a simple example |
209 involving the predefined @{term"map"} functional on lists: |
209 involving the predefined @{term"map"} functional on lists: |
210 *} |
210 \<close> |
211 |
211 |
212 lemma "map f (sep x xs) = sep (f x) (map f xs)" |
212 lemma "map f (sep x xs) = sep (f x) (map f xs)" |
213 |
213 |
214 txt{*\noindent |
214 txt\<open>\noindent |
215 Note that @{term"map f xs"} |
215 Note that @{term"map f xs"} |
216 is the result of applying @{term"f"} to all elements of @{term"xs"}. We prove |
216 is the result of applying @{term"f"} to all elements of @{term"xs"}. We prove |
217 this lemma by recursion induction over @{term"sep"}: |
217 this lemma by recursion induction over @{term"sep"}: |
218 *} |
218 \<close> |
219 |
219 |
220 apply(induct_tac x xs rule: sep.induct) |
220 apply(induct_tac x xs rule: sep.induct) |
221 |
221 |
222 txt{*\noindent |
222 txt\<open>\noindent |
223 The resulting proof state has three subgoals corresponding to the three |
223 The resulting proof state has three subgoals corresponding to the three |
224 clauses for @{term"sep"}: |
224 clauses for @{term"sep"}: |
225 @{subgoals[display,indent=0]} |
225 @{subgoals[display,indent=0]} |
226 The rest is pure simplification: |
226 The rest is pure simplification: |
227 *} |
227 \<close> |
228 |
228 |
229 apply simp_all |
229 apply simp_all |
230 done |
230 done |
231 |
231 |
232 text{*\noindent The proof goes smoothly because the induction rule |
232 text\<open>\noindent The proof goes smoothly because the induction rule |
233 follows the recursion of @{const sep}. Try proving the above lemma by |
233 follows the recursion of @{const sep}. Try proving the above lemma by |
234 structural induction, and you find that you need an additional case |
234 structural induction, and you find that you need an additional case |
235 distinction. |
235 distinction. |
236 |
236 |
237 In general, the format of invoking recursion induction is |
237 In general, the format of invoking recursion induction is |