doc-src/TutorialI/Datatype/Nested.thy
author nipkow
Wed, 24 Jan 2001 12:29:10 +0100
changeset 10971 6852682eaf16
parent 10795 9e888d60d3e5
child 11256 49afcce3bada
permissions -rw-r--r--
*** empty log message ***
nipkow@8745
     1
(*<*)
nipkow@9792
     2
theory Nested = ABexpr:
nipkow@8745
     3
(*>*)
nipkow@8745
     4
nipkow@8745
     5
text{*
nipkow@8745
     6
So far, all datatypes had the property that on the right-hand side of their
nipkow@8745
     7
definition they occurred only at the top-level, i.e.\ directly below a
nipkow@8745
     8
constructor. This is not the case any longer for the following model of terms
nipkow@8745
     9
where function symbols can be applied to a list of arguments:
nipkow@8745
    10
*}
nipkow@9933
    11
(*<*)hide const Var(*>*)
nipkow@10971
    12
datatype ('v,'f)"term" = Var 'v | App 'f "('v,'f)term list";
nipkow@8745
    13
nipkow@8745
    14
text{*\noindent
nipkow@10171
    15
Note that we need to quote @{text term} on the left to avoid confusion with
nipkow@10171
    16
the Isabelle command \isacommand{term}.
nipkow@10971
    17
Parameter @{typ"'v"} is the type of variables and @{typ"'f"} the type of
nipkow@8745
    18
function symbols.
nipkow@9541
    19
A mathematical term like $f(x,g(y))$ becomes @{term"App f [Var x, App g
nipkow@10171
    20
  [Var y]]"}, where @{term f}, @{term g}, @{term x}, @{term y} are
nipkow@8745
    21
suitable values, e.g.\ numbers or strings.
nipkow@8745
    22
nipkow@10171
    23
What complicates the definition of @{text term} is the nested occurrence of
nipkow@10171
    24
@{text term} inside @{text list} on the right-hand side. In principle,
nipkow@8745
    25
nested recursion can be eliminated in favour of mutual recursion by unfolding
nipkow@10171
    26
the offending datatypes, here @{text list}. The result for @{text term}
nipkow@8745
    27
would be something like
nipkow@8751
    28
\medskip
nipkow@8751
    29
nipkow@8751
    30
\input{Datatype/document/unfoldnested.tex}
nipkow@8751
    31
\medskip
nipkow@8751
    32
nipkow@8751
    33
\noindent
nipkow@8745
    34
Although we do not recommend this unfolding to the user, it shows how to
nipkow@8745
    35
simulate nested recursion by mutual recursion.
nipkow@10171
    36
Now we return to the initial definition of @{text term} using
nipkow@8745
    37
nested recursion.
nipkow@8745
    38
nipkow@8745
    39
Let us define a substitution function on terms. Because terms involve term
nipkow@8745
    40
lists, we need to define two substitution functions simultaneously:
nipkow@8745
    41
*}
nipkow@8745
    42
nipkow@8745
    43
consts
nipkow@10971
    44
subst :: "('v\<Rightarrow>('v,'f)term) \<Rightarrow> ('v,'f)term      \<Rightarrow> ('v,'f)term"
nipkow@10971
    45
substs:: "('v\<Rightarrow>('v,'f)term) \<Rightarrow> ('v,'f)term list \<Rightarrow> ('v,'f)term list";
nipkow@8745
    46
nipkow@8745
    47
primrec
nipkow@8745
    48
  "subst s (Var x) = s x"
nipkow@9644
    49
  subst_App:
nipkow@8745
    50
  "subst s (App f ts) = App f (substs s ts)"
nipkow@8745
    51
nipkow@8745
    52
  "substs s [] = []"
nipkow@8745
    53
  "substs s (t # ts) = subst s t # substs s ts";
nipkow@8745
    54
nipkow@8745
    55
text{*\noindent
nipkow@10171
    56
Individual equations in a primrec definition may be named as shown for @{thm[source]subst_App}.
nipkow@10171
    57
The significance of this device will become apparent below.
nipkow@9644
    58
nipkow@8745
    59
Similarly, when proving a statement about terms inductively, we need
nipkow@8745
    60
to prove a related statement about term lists simultaneously. For example,
nipkow@8745
    61
the fact that the identity substitution does not change a term needs to be
nipkow@8745
    62
strengthened and proved as follows:
nipkow@8745
    63
*}
nipkow@8745
    64
nipkow@10971
    65
lemma "subst  Var t  = (t ::('v,'f)term)  \<and>
nipkow@10971
    66
        substs Var ts = (ts::('v,'f)term list)";
nipkow@10171
    67
apply(induct_tac t and ts, simp_all);
nipkow@10171
    68
done
nipkow@8745
    69
nipkow@8745
    70
text{*\noindent
nipkow@10171
    71
Note that @{term Var} is the identity substitution because by definition it
nipkow@9792
    72
leaves variables unchanged: @{prop"subst Var (Var x) = Var x"}. Note also
nipkow@8745
    73
that the type annotations are necessary because otherwise there is nothing in
nipkow@8745
    74
the goal to enforce that both halves of the goal talk about the same type
nipkow@10971
    75
parameters @{text"('v,'f)"}. As a result, induction would fail
nipkow@8745
    76
because the two halves of the goal would be unrelated.
nipkow@8745
    77
nipkow@8745
    78
\begin{exercise}
nipkow@8745
    79
The fact that substitution distributes over composition can be expressed
nipkow@8745
    80
roughly as follows:
nipkow@10178
    81
@{text[display]"subst (f \<circ> g) t = subst f (subst g t)"}
nipkow@8745
    82
Correct this statement (you will find that it does not type-check),
nipkow@10178
    83
strengthen it, and prove it. (Note: @{text"\<circ>"} is function composition;
nipkow@9792
    84
its definition is found in theorem @{thm[source]o_def}).
nipkow@8745
    85
\end{exercise}
nipkow@9644
    86
\begin{exercise}\label{ex:trev-trev}
nipkow@10971
    87
  Define a function @{term trev} of type @{typ"('v,'f)term => ('v,'f)term"}
nipkow@9792
    88
that recursively reverses the order of arguments of all function symbols in a
nipkow@9792
    89
  term. Prove that @{prop"trev(trev t) = t"}.
nipkow@9644
    90
\end{exercise}
nipkow@9644
    91
paulson@10795
    92
The experienced functional programmer may feel that our definition of
paulson@10795
    93
@{term subst} is too complicated in that @{term substs} is
paulson@10795
    94
unnecessary. The @{term App}-case can be defined directly as
nipkow@9644
    95
@{term[display]"subst s (App f ts) = App f (map (subst s) ts)"}
nipkow@9644
    96
where @{term"map"} is the standard list function such that
nipkow@9792
    97
@{text"map f [x1,...,xn] = [f x1,...,f xn]"}. This is true, but Isabelle
paulson@10795
    98
insists on the conjunctive format. Fortunately, we can easily \emph{prove}
nipkow@9792
    99
that the suggested equation holds:
nipkow@9644
   100
*}
nipkow@9644
   101
nipkow@9644
   102
lemma [simp]: "subst s (App f ts) = App f (map (subst s) ts)"
nipkow@10171
   103
apply(induct_tac ts, simp_all)
nipkow@10171
   104
done
nipkow@9644
   105
nipkow@9689
   106
text{*\noindent
nipkow@9644
   107
What is more, we can now disable the old defining equation as a
nipkow@9644
   108
simplification rule:
nipkow@9644
   109
*}
nipkow@9644
   110
nipkow@9933
   111
declare subst_App [simp del]
nipkow@9644
   112
nipkow@9644
   113
text{*\noindent
nipkow@10171
   114
The advantage is that now we have replaced @{term substs} by
nipkow@10171
   115
@{term map}, we can profit from the large number of pre-proved lemmas
nipkow@10171
   116
about @{term map}.  Unfortunately inductive proofs about type
nipkow@10171
   117
@{text term} are still awkward because they expect a conjunction. One
nipkow@9689
   118
could derive a new induction principle as well (see
paulson@10795
   119
\S\ref{sec:derive-ind}), but simpler is to stop using \isacommand{primrec}
paulson@10795
   120
and to define functions with \isacommand{recdef} instead.
nipkow@10186
   121
The details are explained in \S\ref{sec:nested-recdef} below.
nipkow@8745
   122
nipkow@10971
   123
Of course, you may also combine mutual and nested recursion of datatypes. For example,
nipkow@10171
   124
constructor @{text Sum} in \S\ref{sec:datatype-mut-rec} could take a list of
nipkow@10171
   125
expressions as its argument: @{text Sum}~@{typ[quotes]"'a aexp list"}.
nipkow@8745
   126
*}
nipkow@8745
   127
(*<*)
nipkow@8745
   128
end
nipkow@10171
   129
(*>*)