1 (*<*)theory Pairs imports Main begin(*>*)
3 section{*Pairs and Tuples*}
5 text{*\label{sec:products}
6 Ordered pairs were already introduced in \S\ref{sec:pairs}, but only with a minimal
7 repertoire of operations: pairing and the two projections @{term fst} and
8 @{term snd}. In any non-trivial application of pairs you will find that this
9 quickly leads to unreadable nests of projections. This
10 section introduces syntactic sugar to overcome this
11 problem: pattern matching with tuples.
14 subsection{*Pattern Matching with Tuples*}
17 Tuples may be used as patterns in $\lambda$-abstractions,
18 for example @{text"\<lambda>(x,y,z).x+y+z"} and @{text"\<lambda>((x,y),z).x+y+z"}. In fact,
19 tuple patterns can be used in most variable binding constructs,
20 and they can be nested. Here are
21 some typical examples:
23 @{term"let (x,y) = f z in (y,x)"}\\
24 @{term"case xs of [] => (0::nat) | (x,y)#zs => x+y"}\\
25 @{text"\<forall>(x,y)\<in>A. x=y"}\\
26 @{text"{(x,y,z). x=z}"}\\
27 @{term"\<Union>(x,y)\<in>A. {x+y}"}
29 The intuitive meanings of these expressions should be obvious.
30 Unfortunately, we need to know in more detail what the notation really stands
31 for once we have to reason about it. Abstraction
32 over pairs and tuples is merely a convenient shorthand for a more complex
33 internal representation. Thus the internal and external form of a term may
34 differ, which can affect proofs. If you want to avoid this complication,
35 stick to @{term fst} and @{term snd} and write @{term"%p. fst p + snd p"}
36 instead of @{text"\<lambda>(x,y). x+y"}. These terms are distinct even though they
37 denote the same function.
39 Internally, @{term"%(x,y). t"} becomes @{text"split (\<lambda>x y. t)"}, where
40 \cdx{split} is the uncurrying function of type @{text"('a \<Rightarrow> 'b
41 \<Rightarrow> 'c) \<Rightarrow> 'a \<times> 'b \<Rightarrow> 'c"} defined as
44 \hfill(@{thm[source]split_def})
47 other variable binding constructs is translated similarly. Thus we need to
48 understand how to reason about such constructs.
51 subsection{*Theorem Proving*}
54 The most obvious approach is the brute force expansion of @{term split}:
57 lemma "(\<lambda>(x,y).x) p = fst p"
58 by(simp add: split_def)
61 This works well if rewriting with @{thm[source]split_def} finishes the
62 proof, as it does above. But if it does not, you end up with exactly what
63 we are trying to avoid: nests of @{term fst} and @{term snd}. Thus this
64 approach is neither elegant nor very practical in large examples, although it
65 can be effective in small ones.
67 If we consider why this lemma presents a problem,
68 we realize that we need to replace variable~@{term
69 p} by some pair @{term"(a,b)"}. Then both sides of the
70 equation would simplify to @{term a} by the simplification rules
71 @{thm split_conv[no_vars]} and @{thm fst_conv[no_vars]}.
72 To reason about tuple patterns requires some way of
73 converting a variable of product type into a pair.
74 In case of a subterm of the form @{term"split f p"} this is easy: the split
75 rule @{thm[source]split_split} replaces @{term p} by a pair:%
76 \index{*split (method)}
79 lemma "(\<lambda>(x,y).y) p = snd p"
80 apply(split split_split);
83 @{subgoals[display,indent=0]}
84 This subgoal is easily proved by simplification. Thus we could have combined
85 simplification and splitting in one command that proves the goal outright:
89 lemma "(\<lambda>(x,y).y) p = snd p"(*>*)
90 by(simp split: split_split)
93 Let us look at a second example:
96 lemma "let (x,y) = p in fst p = x";
97 apply(simp only: Let_def)
100 @{subgoals[display,indent=0]}
101 A paired @{text let} reduces to a paired $\lambda$-abstraction, which
102 can be split as above. The same is true for paired set comprehension:
105 (*<*)by(simp split: split_split)(*>*)
106 lemma "p \<in> {(x,y). x=y} \<longrightarrow> fst p = snd p"
110 @{subgoals[display,indent=0]}
111 Again, simplification produces a term suitable for @{thm[source]split_split}
112 as above. If you are worried about the strange form of the premise:
113 @{text"split (op =)"} is short for @{term"\<lambda>(x,y). x=y"}.
114 The same proof procedure works for
117 (*<*)by(simp split: split_split)(*>*)
118 lemma "p \<in> {(x,y). x=y} \<Longrightarrow> fst p = snd p"
121 except that we now have to use @{thm[source]split_split_asm}, because
122 @{term split} occurs in the assumptions.
124 However, splitting @{term split} is not always a solution, as no @{term split}
125 may be present in the goal. Consider the following function:
128 (*<*)by(simp split: split_split_asm)(*>*)
129 primrec swap :: "'a \<times> 'b \<Rightarrow> 'b \<times> 'a" where "swap (x,y) = (y,x)"
132 Note that the above \isacommand{primrec} definition is admissible
133 because @{text"\<times>"} is a datatype. When we now try to prove
136 lemma "swap(swap p) = p"
139 simplification will do nothing, because the defining equation for
140 @{const[source] swap} expects a pair. Again, we need to turn @{term p}
141 into a pair first, but this time there is no @{term split} in sight.
142 The only thing we can do is to split the term by hand:
147 @{subgoals[display,indent=0]}
148 Again, \methdx{case_tac} is applicable because @{text"\<times>"} is a datatype.
149 The subgoal is easily proved by @{text simp}.
151 Splitting by @{text case_tac} also solves the previous examples and may thus
152 appear preferable to the more arcane methods introduced first. However, see
153 the warning about @{text case_tac} in \S\ref{sec:struct-ind-case}.
155 Alternatively, you can split \emph{all} @{text"\<And>"}-quantified variables
156 in a goal with the rewrite rule @{thm[source]split_paired_all}:
160 lemma "\<And>p q. swap(swap p) = q \<longrightarrow> p = q"
161 apply(simp only: split_paired_all)
164 @{subgoals[display,indent=0,margin=70]}
171 Note that we have intentionally included only @{thm[source]split_paired_all}
172 in the first simplification step, and then we simplify again.
173 This time the reason was not merely
175 @{thm[source]split_paired_all} may interfere with other functions
177 The following command could fail (here it does not)
178 where two separate \isa{simp} applications succeed.
182 lemma "\<And>p q. swap(swap p) = q \<longrightarrow> p = q"
184 apply(simp add: split_paired_all)
187 Finally, the simplifier automatically splits all @{text"\<forall>"} and
188 @{text"\<exists>"}-quantified variables:
191 lemma "\<forall>p. \<exists>q. swap p = swap q"
195 To turn off this automatic splitting, disable the
196 responsible simplification rules:
198 @{thm split_paired_All[no_vars]}
200 (@{thm[source]split_paired_All})\\
201 @{thm split_paired_Ex[no_vars]}
203 (@{thm[source]split_paired_Ex})