doc-src/TutorialI/Types/Pairs.thy
author Walther Neuper <neuper@ist.tugraz.at>
Thu, 12 Aug 2010 15:03:34 +0200
branchisac-from-Isabelle2009-2
changeset 37913 20e3616b2d9c
parent 27170 65bb0ddb0b9f
permissions -rw-r--r--
prepare reactivation of isac-update-Isa09-2
nipkow@27170
     1
(*<*)theory Pairs imports Main begin(*>*)
nipkow@10560
     2
paulson@11428
     3
section{*Pairs and Tuples*}
nipkow@10560
     4
nipkow@10560
     5
text{*\label{sec:products}
paulson@11428
     6
Ordered pairs were already introduced in \S\ref{sec:pairs}, but only with a minimal
nipkow@10560
     7
repertoire of operations: pairing and the two projections @{term fst} and
nipkow@11149
     8
@{term snd}. In any non-trivial application of pairs you will find that this
paulson@11494
     9
quickly leads to unreadable nests of projections. This
paulson@11494
    10
section introduces syntactic sugar to overcome this
nipkow@10560
    11
problem: pattern matching with tuples.
nipkow@10560
    12
*}
nipkow@10560
    13
paulson@10885
    14
subsection{*Pattern Matching with Tuples*}
nipkow@10560
    15
nipkow@10560
    16
text{*
paulson@10885
    17
Tuples may be used as patterns in $\lambda$-abstractions,
nipkow@10560
    18
for example @{text"\<lambda>(x,y,z).x+y+z"} and @{text"\<lambda>((x,y),z).x+y+z"}. In fact,
paulson@10885
    19
tuple patterns can be used in most variable binding constructs,
paulson@10885
    20
and they can be nested. Here are
nipkow@10560
    21
some typical examples:
nipkow@10560
    22
\begin{quote}
nipkow@10560
    23
@{term"let (x,y) = f z in (y,x)"}\\
nipkow@12699
    24
@{term"case xs of [] => (0::nat) | (x,y)#zs => x+y"}\\
nipkow@10560
    25
@{text"\<forall>(x,y)\<in>A. x=y"}\\
paulson@10885
    26
@{text"{(x,y,z). x=z}"}\\
nipkow@10560
    27
@{term"\<Union>(x,y)\<in>A. {x+y}"}
nipkow@10560
    28
\end{quote}
paulson@10885
    29
The intuitive meanings of these expressions should be obvious.
nipkow@10560
    30
Unfortunately, we need to know in more detail what the notation really stands
paulson@10885
    31
for once we have to reason about it.  Abstraction
nipkow@10560
    32
over pairs and tuples is merely a convenient shorthand for a more complex
nipkow@10560
    33
internal representation.  Thus the internal and external form of a term may
nipkow@10560
    34
differ, which can affect proofs. If you want to avoid this complication,
nipkow@10560
    35
stick to @{term fst} and @{term snd} and write @{term"%p. fst p + snd p"}
paulson@11494
    36
instead of @{text"\<lambda>(x,y). x+y"}.  These terms are distinct even though they
paulson@11494
    37
denote the same function.
nipkow@10560
    38
nipkow@10560
    39
Internally, @{term"%(x,y). t"} becomes @{text"split (\<lambda>x y. t)"}, where
paulson@11494
    40
\cdx{split} is the uncurrying function of type @{text"('a \<Rightarrow> 'b
nipkow@10560
    41
\<Rightarrow> 'c) \<Rightarrow> 'a \<times> 'b \<Rightarrow> 'c"} defined as
nipkow@10560
    42
\begin{center}
nipkow@10560
    43
@{thm split_def}
nipkow@10560
    44
\hfill(@{thm[source]split_def})
nipkow@10560
    45
\end{center}
nipkow@10560
    46
Pattern matching in
nipkow@10560
    47
other variable binding constructs is translated similarly. Thus we need to
nipkow@10560
    48
understand how to reason about such constructs.
nipkow@10560
    49
*}
nipkow@10560
    50
paulson@10885
    51
subsection{*Theorem Proving*}
nipkow@10560
    52
nipkow@10560
    53
text{*
nipkow@10560
    54
The most obvious approach is the brute force expansion of @{term split}:
nipkow@10560
    55
*}
nipkow@10560
    56
nipkow@10560
    57
lemma "(\<lambda>(x,y).x) p = fst p"
wenzelm@12815
    58
by(simp add: split_def)
nipkow@10560
    59
nipkow@27027
    60
text{* \noindent
nipkow@27027
    61
This works well if rewriting with @{thm[source]split_def} finishes the
nipkow@11149
    62
proof, as it does above.  But if it does not, you end up with exactly what
nipkow@10560
    63
we are trying to avoid: nests of @{term fst} and @{term snd}. Thus this
nipkow@10560
    64
approach is neither elegant nor very practical in large examples, although it
nipkow@10560
    65
can be effective in small ones.
nipkow@10560
    66
paulson@11494
    67
If we consider why this lemma presents a problem, 
nipkow@27027
    68
we realize that we need to replace variable~@{term
paulson@11494
    69
p} by some pair @{term"(a,b)"}.  Then both sides of the
paulson@11494
    70
equation would simplify to @{term a} by the simplification rules
paulson@11494
    71
@{thm split_conv[no_vars]} and @{thm fst_conv[no_vars]}.  
paulson@11494
    72
To reason about tuple patterns requires some way of
paulson@11494
    73
converting a variable of product type into a pair.
nipkow@10560
    74
In case of a subterm of the form @{term"split f p"} this is easy: the split
paulson@11494
    75
rule @{thm[source]split_split} replaces @{term p} by a pair:%
paulson@11494
    76
\index{*split (method)}
nipkow@10560
    77
*}
nipkow@10560
    78
nipkow@10560
    79
lemma "(\<lambda>(x,y).y) p = snd p"
nipkow@10654
    80
apply(split split_split);
nipkow@10560
    81
nipkow@10560
    82
txt{*
nipkow@10560
    83
@{subgoals[display,indent=0]}
nipkow@10824
    84
This subgoal is easily proved by simplification. Thus we could have combined
nipkow@10824
    85
simplification and splitting in one command that proves the goal outright:
nipkow@10824
    86
*}
nipkow@10824
    87
(*<*)
nipkow@10824
    88
by simp
nipkow@10824
    89
lemma "(\<lambda>(x,y).y) p = snd p"(*>*)
nipkow@10824
    90
by(simp split: split_split)
nipkow@10560
    91
nipkow@10824
    92
text{*
nipkow@10560
    93
Let us look at a second example:
nipkow@10560
    94
*}
nipkow@10560
    95
nipkow@10560
    96
lemma "let (x,y) = p in fst p = x";
nipkow@10824
    97
apply(simp only: Let_def)
nipkow@10560
    98
nipkow@10560
    99
txt{*
nipkow@10560
   100
@{subgoals[display,indent=0]}
nipkow@10560
   101
A paired @{text let} reduces to a paired $\lambda$-abstraction, which
nipkow@10560
   102
can be split as above. The same is true for paired set comprehension:
nipkow@10560
   103
*}
nipkow@10560
   104
wenzelm@12815
   105
(*<*)by(simp split: split_split)(*>*)
nipkow@10560
   106
lemma "p \<in> {(x,y). x=y} \<longrightarrow> fst p = snd p"
nipkow@10560
   107
apply simp
nipkow@10560
   108
nipkow@10560
   109
txt{*
nipkow@10560
   110
@{subgoals[display,indent=0]}
nipkow@10560
   111
Again, simplification produces a term suitable for @{thm[source]split_split}
nipkow@11277
   112
as above. If you are worried about the strange form of the premise:
nipkow@27169
   113
@{text"split (op =)"} is short for @{term"\<lambda>(x,y). x=y"}.
nipkow@11277
   114
The same proof procedure works for
nipkow@10560
   115
*}
nipkow@10560
   116
wenzelm@12815
   117
(*<*)by(simp split: split_split)(*>*)
nipkow@10560
   118
lemma "p \<in> {(x,y). x=y} \<Longrightarrow> fst p = snd p"
nipkow@10560
   119
nipkow@10560
   120
txt{*\noindent
nipkow@10560
   121
except that we now have to use @{thm[source]split_split_asm}, because
nipkow@10560
   122
@{term split} occurs in the assumptions.
nipkow@10560
   123
nipkow@10560
   124
However, splitting @{term split} is not always a solution, as no @{term split}
nipkow@10560
   125
may be present in the goal. Consider the following function:
nipkow@10560
   126
*}
nipkow@10560
   127
wenzelm@12815
   128
(*<*)by(simp split: split_split_asm)(*>*)
nipkow@27027
   129
primrec swap :: "'a \<times> 'b \<Rightarrow> 'b \<times> 'a" where "swap (x,y) = (y,x)"
nipkow@10560
   130
nipkow@10560
   131
text{*\noindent
nipkow@10560
   132
Note that the above \isacommand{primrec} definition is admissible
nipkow@10560
   133
because @{text"\<times>"} is a datatype. When we now try to prove
nipkow@10560
   134
*}
nipkow@10560
   135
nipkow@10560
   136
lemma "swap(swap p) = p"
nipkow@10560
   137
nipkow@10560
   138
txt{*\noindent
nipkow@27027
   139
simplification will do nothing, because the defining equation for
nipkow@27027
   140
@{const[source] swap} expects a pair. Again, we need to turn @{term p}
nipkow@27027
   141
into a pair first, but this time there is no @{term split} in sight.
nipkow@27027
   142
The only thing we can do is to split the term by hand:
nipkow@10560
   143
*}
nipkow@10560
   144
apply(case_tac p)
nipkow@10560
   145
nipkow@10560
   146
txt{*\noindent
nipkow@10560
   147
@{subgoals[display,indent=0]}
paulson@11494
   148
Again, \methdx{case_tac} is applicable because @{text"\<times>"} is a datatype.
nipkow@10560
   149
The subgoal is easily proved by @{text simp}.
nipkow@10560
   150
nipkow@10824
   151
Splitting by @{text case_tac} also solves the previous examples and may thus
nipkow@10824
   152
appear preferable to the more arcane methods introduced first. However, see
nipkow@10824
   153
the warning about @{text case_tac} in \S\ref{sec:struct-ind-case}.
nipkow@10824
   154
nipkow@27027
   155
Alternatively, you can split \emph{all} @{text"\<And>"}-quantified variables
nipkow@27027
   156
in a goal with the rewrite rule @{thm[source]split_paired_all}:
nipkow@10560
   157
*}
nipkow@10560
   158
nipkow@10560
   159
(*<*)by simp(*>*)
nipkow@10560
   160
lemma "\<And>p q. swap(swap p) = q \<longrightarrow> p = q"
wenzelm@12631
   161
apply(simp only: split_paired_all)
nipkow@10560
   162
nipkow@10560
   163
txt{*\noindent
nipkow@27027
   164
@{subgoals[display,indent=0,margin=70]}
nipkow@10560
   165
*}
nipkow@10560
   166
nipkow@10560
   167
apply simp
nipkow@10560
   168
done
nipkow@10560
   169
nipkow@10560
   170
text{*\noindent
nipkow@10560
   171
Note that we have intentionally included only @{thm[source]split_paired_all}
paulson@11494
   172
in the first simplification step, and then we simplify again. 
paulson@11494
   173
This time the reason was not merely
nipkow@10560
   174
pedagogical:
paulson@11494
   175
@{thm[source]split_paired_all} may interfere with other functions
paulson@11494
   176
of the simplifier.
paulson@11494
   177
The following command could fail (here it does not)
paulson@11494
   178
where two separate \isa{simp} applications succeed.
nipkow@10560
   179
*}
nipkow@10560
   180
nipkow@10560
   181
(*<*)
nipkow@10560
   182
lemma "\<And>p q. swap(swap p) = q \<longrightarrow> p = q"
nipkow@10560
   183
(*>*)
wenzelm@12815
   184
apply(simp add: split_paired_all)
nipkow@10560
   185
(*<*)done(*>*)
nipkow@10560
   186
text{*\noindent
paulson@11494
   187
Finally, the simplifier automatically splits all @{text"\<forall>"} and
paulson@11494
   188
@{text"\<exists>"}-quantified variables:
nipkow@10560
   189
*}
nipkow@10560
   190
nipkow@10560
   191
lemma "\<forall>p. \<exists>q. swap p = swap q"
paulson@11494
   192
by simp;
nipkow@10560
   193
nipkow@10560
   194
text{*\noindent
nipkow@27027
   195
To turn off this automatic splitting, disable the
nipkow@10560
   196
responsible simplification rules:
nipkow@10560
   197
\begin{center}
nipkow@10654
   198
@{thm split_paired_All[no_vars]}
nipkow@10560
   199
\hfill
nipkow@10560
   200
(@{thm[source]split_paired_All})\\
nipkow@10654
   201
@{thm split_paired_Ex[no_vars]}
nipkow@10560
   202
\hfill
nipkow@10560
   203
(@{thm[source]split_paired_Ex})
nipkow@10560
   204
\end{center}
nipkow@10560
   205
*}
nipkow@10560
   206
(*<*)
nipkow@10560
   207
end
nipkow@10560
   208
(*>*)