src/Doc/Tutorial/Fun/fun0.thy
author wenzelm
Sat, 05 Jan 2019 17:24:33 +0100
changeset 69597 ff784d5a5bfb
parent 69505 cc2d676d5395
child 76987 4c275405faae
permissions -rw-r--r--
isabelle update -u control_cartouches;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     1
(*<*)
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     2
theory fun0 imports Main begin
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     3
(*>*)
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     4
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
     5
text\<open>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     6
\subsection{Definition}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     7
\label{sec:fun-examples}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     8
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
     9
Here is a simple example, the \rmindex{Fibonacci function}:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    10
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    11
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    12
fun fib :: "nat \<Rightarrow> nat" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    13
"fib 0 = 0" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    14
"fib (Suc 0) = 1" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    15
"fib (Suc(Suc x)) = fib x + fib (Suc x)"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    16
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    17
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    18
This resembles ordinary functional programming languages. Note the obligatory
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    19
\isacommand{where} and \isa{|}. Command \isacommand{fun} declares and
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    20
defines the function in one go. Isabelle establishes termination automatically
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
    21
because \<^const>\<open>fib\<close>'s argument decreases in every recursive call.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    22
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    23
Slightly more interesting is the insertion of a fixed element
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    24
between any two elements of a list:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    25
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    26
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    27
fun sep :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    28
"sep a []     = []" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    29
"sep a [x]    = [x]" |
58860
fee7cfa69c50 eliminated spurious semicolons;
wenzelm
parents: 58620
diff changeset
    30
"sep a (x#y#zs) = x # a # sep a (y#zs)"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    31
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    32
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    33
This time the length of the list decreases with the
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    34
recursive call; the first argument is irrelevant for termination.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    35
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    36
Pattern matching\index{pattern matching!and \isacommand{fun}}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    37
need not be exhaustive and may employ wildcards:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    38
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    39
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    40
fun last :: "'a list \<Rightarrow> 'a" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    41
"last [x]      = x" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    42
"last (_#y#zs) = last (y#zs)"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    43
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    44
text\<open>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    45
Overlapping patterns are disambiguated by taking the order of equations into
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    46
account, just as in functional programming:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    47
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    48
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    49
fun sep1 :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    50
"sep1 a (x#y#zs) = x # a # sep1 a (y#zs)" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    51
"sep1 _ xs       = xs"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    52
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    53
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    54
To guarantee that the second equation can only be applied if the first
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    55
one does not match, Isabelle internally replaces the second equation
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
    56
by the two possibilities that are left: \<^prop>\<open>sep1 a [] = []\<close> and
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
    57
\<^prop>\<open>sep1 a [x] = [x]\<close>.  Thus the functions \<^const>\<open>sep\<close> and
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
    58
\<^const>\<open>sep1\<close> are identical.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    59
25263
b54744935036 *** empty log message ***
nipkow
parents: 25261
diff changeset
    60
Because of its pattern matching syntax, \isacommand{fun} is also useful
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    61
for the definition of non-recursive functions:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    62
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    63
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    64
fun swap12 :: "'a list \<Rightarrow> 'a list" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    65
"swap12 (x#y#zs) = y#x#zs" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    66
"swap12 zs       = zs"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    67
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    68
text\<open>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    69
After a function~$f$ has been defined via \isacommand{fun},
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    70
its defining equations (or variants derived from them) are available
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
    71
under the name $f$\<open>.simps\<close> as theorems.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    72
For example, look (via \isacommand{thm}) at
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    73
@{thm[source]sep.simps} and @{thm[source]sep1.simps} to see that they define
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    74
the same function. What is more, those equations are automatically declared as
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    75
simplification rules.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    76
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    77
\subsection{Termination}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    78
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    79
Isabelle's automatic termination prover for \isacommand{fun} has a
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
    80
fixed notion of the \emph{size} (of type \<^typ>\<open>nat\<close>) of an
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    81
argument. The size of a natural number is the number itself. The size
25339
nipkow
parents: 25265
diff changeset
    82
of a list is its length. For the general case see \S\ref{sec:general-datatype}.
nipkow
parents: 25265
diff changeset
    83
A recursive function is accepted if \isacommand{fun} can
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    84
show that the size of one fixed argument becomes smaller with each
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    85
recursive call.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    86
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
    87
More generally, \isacommand{fun} allows any \emph{lexicographic
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    88
combination} of size measures in case there are multiple
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
    89
arguments. For example, the following version of \rmindex{Ackermann's
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    90
function} is accepted:\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    91
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    92
fun ack2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    93
"ack2 n 0 = Suc n" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    94
"ack2 0 (Suc m) = ack2 (Suc 0) m" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
    95
"ack2 (Suc n) (Suc m) = ack2 (ack2 n (Suc m)) m"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    96
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
    97
text\<open>The order of arguments has no influence on whether
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
    98
\isacommand{fun} can prove termination of a function. For more details
58620
7435b6a3f72e more antiquotations;
wenzelm
parents: 48985
diff changeset
    99
see elsewhere~@{cite bulwahnKN07}.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   100
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   101
\subsection{Simplification}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   102
\label{sec:fun-simplification}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   103
25265
3a5d33e8a019 tweaked
paulson
parents: 25263
diff changeset
   104
Upon a successful termination proof, the recursion equations become
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   105
simplification rules, just as with \isacommand{primrec}.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   106
In most cases this works fine, but there is a subtle
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   107
problem that must be mentioned: simplification may not
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   108
terminate because of automatic splitting of \<open>if\<close>.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   109
\index{*if expressions!splitting of}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   110
Let us look at an example:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   111
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   112
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   113
fun gcd :: "nat \<Rightarrow> nat \<Rightarrow> nat" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
   114
"gcd m n = (if n=0 then m else gcd n (m mod n))"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   115
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   116
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   117
The second argument decreases with each recursive call.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   118
The termination condition
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   119
@{prop[display]"n ~= (0::nat) ==> m mod n < n"}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   120
is proved automatically because it is already present as a lemma in
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   121
HOL\@.  Thus the recursion equation becomes a simplification
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   122
rule. Of course the equation is nonterminating if we are allowed to unfold
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   123
the recursive call inside the \<open>else\<close> branch, which is why programming
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   124
languages and our simplifier don't do that. Unfortunately the simplifier does
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   125
something else that leads to the same problem: it splits 
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   126
each \<open>if\<close>-expression unless its
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   127
condition simplifies to \<^term>\<open>True\<close> or \<^term>\<open>False\<close>.  For
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   128
example, simplification reduces
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   129
@{prop[display]"gcd m n = k"}
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   130
in one step to
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   131
@{prop[display]"(if n=0 then m else gcd n (m mod n)) = k"}
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   132
where the condition cannot be reduced further, and splitting leads to
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   133
@{prop[display]"(n=0 --> m=k) & (n ~= 0 --> gcd n (m mod n)=k)"}
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   134
Since the recursive call \<^term>\<open>gcd n (m mod n)\<close> is no longer protected by
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   135
an \<open>if\<close>, it is unfolded again, which leads to an infinite chain of
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   136
simplification steps. Fortunately, this problem can be avoided in many
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   137
different ways.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   138
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   139
The most radical solution is to disable the offending theorem
62392
747d36865c2c more canonical names
nipkow
parents: 58860
diff changeset
   140
@{thm[source]if_split},
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   141
as shown in \S\ref{sec:AutoCaseSplits}.  However, we do not recommend this
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   142
approach: you will often have to invoke the rule explicitly when
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   143
\<open>if\<close> is involved.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   144
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   145
If possible, the definition should be given by pattern matching on the left
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   146
rather than \<open>if\<close> on the right. In the case of \<^term>\<open>gcd\<close> the
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   147
following alternative definition suggests itself:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   148
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   149
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   150
fun gcd1 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
   151
"gcd1 m 0 = m" |
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
   152
"gcd1 m n = gcd1 n (m mod n)"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   153
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   154
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   155
The order of equations is important: it hides the side condition
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   156
\<^prop>\<open>n ~= (0::nat)\<close>.  Unfortunately, not all conditionals can be
25263
b54744935036 *** empty log message ***
nipkow
parents: 25261
diff changeset
   157
expressed by pattern matching.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   158
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   159
A simple alternative is to replace \<open>if\<close> by \<open>case\<close>, 
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   160
which is also available for \<^typ>\<open>bool\<close> and is not split automatically:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   161
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   162
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   163
fun gcd2 :: "nat \<Rightarrow> nat \<Rightarrow> nat" where
27015
f8537d69f514 *** empty log message ***
nipkow
parents: 25339
diff changeset
   164
"gcd2 m n = (case n=0 of True \<Rightarrow> m | False \<Rightarrow> gcd2 n (m mod n))"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   165
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   166
text\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   167
This is probably the neatest solution next to pattern matching, and it is
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   168
always available.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   169
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   170
A final alternative is to replace the offending simplification rules by
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   171
derived conditional ones. For \<^term>\<open>gcd\<close> it means we have to prove
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   172
these lemmas:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   173
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   174
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   175
lemma [simp]: "gcd m 0 = m"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   176
apply(simp)
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   177
done
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   178
25261
3dc292be0b54 recdef -> fun
nipkow
parents: 25260
diff changeset
   179
lemma [simp]: "n \<noteq> 0 \<Longrightarrow> gcd m n = gcd n (m mod n)"
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   180
apply(simp)
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   181
done
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   182
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   183
text\<open>\noindent
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   184
Simplification terminates for these proofs because the condition of the \<open>if\<close> simplifies to \<^term>\<open>True\<close> or \<^term>\<open>False\<close>.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   185
Now we can disable the original simplification rule:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   186
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   187
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   188
declare gcd.simps [simp del]
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   189
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   190
text\<open>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   191
\index{induction!recursion|(}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   192
\index{recursion induction|(}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   193
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   194
\subsection{Induction}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   195
\label{sec:fun-induction}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   196
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   197
Having defined a function we might like to prove something about it.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   198
Since the function is recursive, the natural proof principle is
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   199
again induction. But this time the structural form of induction that comes
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   200
with datatypes is unlikely to work well --- otherwise we could have defined the
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   201
function by \isacommand{primrec}. Therefore \isacommand{fun} automatically
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   202
proves a suitable induction rule $f$\<open>.induct\<close> that follows the
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   203
recursion pattern of the particular function $f$. We call this
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   204
\textbf{recursion induction}. Roughly speaking, it
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   205
requires you to prove for each \isacommand{fun} equation that the property
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   206
you are trying to establish holds for the left-hand side provided it holds
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   207
for all recursive calls on the right-hand side. Here is a simple example
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   208
involving the predefined \<^term>\<open>map\<close> functional on lists:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   209
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   210
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   211
lemma "map f (sep x xs) = sep (f x) (map f xs)"
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   212
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   213
txt\<open>\noindent
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   214
Note that \<^term>\<open>map f xs\<close>
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   215
is the result of applying \<^term>\<open>f\<close> to all elements of \<^term>\<open>xs\<close>. We prove
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   216
this lemma by recursion induction over \<^term>\<open>sep\<close>:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   217
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   218
58860
fee7cfa69c50 eliminated spurious semicolons;
wenzelm
parents: 58620
diff changeset
   219
apply(induct_tac x xs rule: sep.induct)
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   220
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   221
txt\<open>\noindent
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   222
The resulting proof state has three subgoals corresponding to the three
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   223
clauses for \<^term>\<open>sep\<close>:
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   224
@{subgoals[display,indent=0]}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   225
The rest is pure simplification:
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   226
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   227
58860
fee7cfa69c50 eliminated spurious semicolons;
wenzelm
parents: 58620
diff changeset
   228
apply simp_all
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   229
done
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   230
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   231
text\<open>\noindent The proof goes smoothly because the induction rule
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   232
follows the recursion of \<^const>\<open>sep\<close>.  Try proving the above lemma by
25263
b54744935036 *** empty log message ***
nipkow
parents: 25261
diff changeset
   233
structural induction, and you find that you need an additional case
b54744935036 *** empty log message ***
nipkow
parents: 25261
diff changeset
   234
distinction.
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   235
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   236
In general, the format of invoking recursion induction is
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   237
\begin{quote}
69505
cc2d676d5395 isabelle update_cartouches -t;
wenzelm
parents: 67406
diff changeset
   238
\isacommand{apply}\<open>(induct_tac\<close> $x@1 \dots x@n$ \<open>rule:\<close> $f$\<open>.induct)\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   239
\end{quote}\index{*induct_tac (method)}%
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   240
where $x@1~\dots~x@n$ is a list of free variables in the subgoal and $f$ the
27167
nipkow
parents: 27015
diff changeset
   241
name of a function that takes $n$ arguments. Usually the subgoal will
25263
b54744935036 *** empty log message ***
nipkow
parents: 25261
diff changeset
   242
contain the term $f x@1 \dots x@n$ but this need not be the case. The
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   243
induction rules do not mention $f$ at all. Here is @{thm[source]sep.induct}:
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   244
\begin{isabelle}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   245
{\isasymlbrakk}~{\isasymAnd}a.~P~a~[];\isanewline
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   246
~~{\isasymAnd}a~x.~P~a~[x];\isanewline
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   247
~~{\isasymAnd}a~x~y~zs.~P~a~(y~\#~zs)~{\isasymLongrightarrow}~P~a~(x~\#~y~\#~zs){\isasymrbrakk}\isanewline
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   248
{\isasymLongrightarrow}~P~u~v%
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   249
\end{isabelle}
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   250
It merely says that in order to prove a property \<^term>\<open>P\<close> of \<^term>\<open>u\<close> and
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   251
\<^term>\<open>v\<close> you need to prove it for the three cases where \<^term>\<open>v\<close> is the
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   252
empty list, the singleton list, and the list with at least two elements.
69597
ff784d5a5bfb isabelle update -u control_cartouches;
wenzelm
parents: 69505
diff changeset
   253
The final case has an induction hypothesis:  you may assume that \<^term>\<open>P\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   254
holds for the tail of that list.
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   255
\index{induction!recursion|)}
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   256
\index{recursion induction|)}
67406
23307fd33906 isabelle update_cartouches -c;
wenzelm
parents: 62392
diff changeset
   257
\<close>
25260
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   258
(*<*)
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   259
end
71b2a1fefb84 added Fun
nipkow
parents:
diff changeset
   260
(*>*)