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