62739
|
1 |
(* Title: Doc/Corec/Corec.thy
|
|
2 |
Author: Jasmin Blanchette, Inria, LORIA, MPII
|
|
3 |
Author: Aymeric Bouzy, Ecole polytechnique
|
|
4 |
Author: Andreas Lochbihler, ETH Zuerich
|
|
5 |
Author: Andrei Popescu, Middlesex University
|
|
6 |
Author: Dmitriy Traytel, ETH Zuerich
|
|
7 |
|
|
8 |
Tutorial for nonprimitively corecursive definitions.
|
|
9 |
*)
|
|
10 |
|
|
11 |
theory Corec
|
|
12 |
imports
|
62742
|
13 |
GCD
|
62739
|
14 |
"../Datatypes/Setup"
|
|
15 |
"~~/src/HOL/Library/BNF_Corec"
|
62742
|
16 |
"~~/src/HOL/Library/FSet"
|
62739
|
17 |
begin
|
|
18 |
|
|
19 |
section \<open>Introduction
|
|
20 |
\label{sec:introduction}\<close>
|
|
21 |
|
|
22 |
text \<open>
|
|
23 |
...
|
|
24 |
\cite{isabelle-datatypes}
|
62742
|
25 |
|
|
26 |
* friend
|
|
27 |
* up to
|
|
28 |
|
|
29 |
BNF
|
|
30 |
|
|
31 |
link to papers
|
62739
|
32 |
\<close>
|
|
33 |
|
|
34 |
|
|
35 |
section \<open>Introductory Examples
|
|
36 |
\label{sec:introductory-examples}\<close>
|
|
37 |
|
62742
|
38 |
text \<open>
|
|
39 |
\<close>
|
|
40 |
|
62739
|
41 |
|
|
42 |
subsection \<open>Simple Corecursion
|
|
43 |
\label{ssec:simple-corecursion}\<close>
|
|
44 |
|
62742
|
45 |
text \<open>
|
|
46 |
The case studies by Rutten~\cite{rutten05} and Hinze~\cite{hinze10} on stream
|
|
47 |
calculi serve as our starting point. Streams can be defined as follows
|
|
48 |
(cf. @{file "~~/src/HOL/Library/Stream.thy"}):
|
|
49 |
\<close>
|
|
50 |
|
|
51 |
codatatype (sset: 'a) stream =
|
|
52 |
SCons (shd: 'a) (stl: "'a stream")
|
|
53 |
for
|
|
54 |
map: smap
|
|
55 |
|
|
56 |
text \<open>
|
|
57 |
The @{command corec} command makes it possible to define functions where the
|
|
58 |
corecursive call occurs under two or more constructors:
|
|
59 |
\<close>
|
|
60 |
|
|
61 |
corec oneTwos :: "nat stream" where
|
|
62 |
"oneTwos = SCons 1 (SCons 2 oneTwos)"
|
|
63 |
|
|
64 |
text \<open>
|
|
65 |
\noindent
|
|
66 |
This is already beyond the syntactic fragment supported by \keyw{primcorec}.
|
|
67 |
|
|
68 |
The following definition of pointwise sum can be performed with either
|
|
69 |
\keyw{primcorec} or @{command corec}:
|
|
70 |
\<close>
|
|
71 |
|
|
72 |
primcorec ssum :: "('a :: plus) stream \<Rightarrow> 'a stream \<Rightarrow> 'a stream" where
|
|
73 |
"ssum xs ys = SCons (shd xs + shd ys) (ssum (stl xs) (stl ys))"
|
|
74 |
|
|
75 |
text \<open>
|
|
76 |
\noindent
|
|
77 |
Pointwise sum meets the friendliness criterion. We register it as a friend using
|
|
78 |
the @{command friend_of_corec} command. The command requires us to give a
|
|
79 |
specification of @{const ssum} where a constructor (@{const SCons}) occurs at
|
|
80 |
the outermost position on the right-hand side. Here, we can simply reuse the
|
|
81 |
\keyw{primcorec} specification above:
|
|
82 |
\<close>
|
|
83 |
|
|
84 |
friend_of_corec ssum :: "('a :: plus) stream \<Rightarrow> 'a stream \<Rightarrow> 'a stream" where
|
|
85 |
"ssum xs ys = SCons (shd xs + shd ys) (ssum (stl xs) (stl ys))"
|
|
86 |
apply (rule ssum.code)
|
|
87 |
by transfer_prover
|
|
88 |
|
|
89 |
text \<open>
|
|
90 |
\noindent
|
|
91 |
The command emits two proof goals. The first one corresponds to the equation we
|
|
92 |
specified and is trivial to discharge. The second one is a parametricity goal
|
|
93 |
and can usually be discharged using the @{text transfer_prover} proof method.
|
|
94 |
|
|
95 |
After registering @{const ssum} as a friend, we can use it in the corecursive
|
|
96 |
call context, either inside or outside the constructor guard:
|
|
97 |
\<close>
|
|
98 |
|
|
99 |
corec fibA :: "nat stream" where
|
|
100 |
"fibA = SCons 0 (ssum (SCons 1 fibA) fibA)"
|
|
101 |
|
|
102 |
text \<open>\blankline\<close>
|
|
103 |
|
|
104 |
corec fibB :: "nat stream" where
|
|
105 |
"fibB = ssum (SCons 0 (SCons 1 fibB)) (SCons 0 fibB)"
|
|
106 |
|
|
107 |
text \<open>
|
|
108 |
Using the @{text "friend"} option, we can simultaneously define a function and
|
|
109 |
register it as a friend:
|
|
110 |
\<close>
|
|
111 |
|
|
112 |
corec (friend)
|
|
113 |
sprod :: "('a :: {plus,times}) stream \<Rightarrow> 'a stream \<Rightarrow> 'a stream"
|
|
114 |
where
|
|
115 |
"sprod xs ys =
|
|
116 |
SCons (shd xs * shd ys) (ssum (sprod xs (stl ys)) (sprod (stl xs) ys))"
|
|
117 |
|
|
118 |
text \<open>\blankline\<close>
|
|
119 |
|
|
120 |
corec (friend) sexp :: "nat stream \<Rightarrow> nat stream" where
|
|
121 |
"sexp xs = SCons (2 ^^ shd xs) (sprod (stl xs) (sexp xs))"
|
|
122 |
|
|
123 |
text \<open>
|
|
124 |
\noindent
|
|
125 |
The parametricity proof goal is given to @{text transfer_prover}.
|
|
126 |
|
|
127 |
The @{const sprod} and @{const sexp} functions provide shuffle product and
|
|
128 |
exponentiation on streams. We can use them to define the stream of factorial
|
|
129 |
numbers in two different ways:
|
|
130 |
\<close>
|
|
131 |
|
|
132 |
corec factA :: "nat stream" where
|
|
133 |
"factA = (let zs = SCons 1 factA in sprod zs zs)"
|
|
134 |
|
|
135 |
corec factB :: "nat stream" where
|
|
136 |
"factB = sexp (SCons 0 factB)"
|
|
137 |
|
|
138 |
text \<open>
|
|
139 |
The arguments of friendly operations can be of complex types involving the
|
|
140 |
target codatatype. The following example defines the supremum of a finite set of
|
|
141 |
streams by primitive corecursion and registers it as friendly:
|
|
142 |
\<close>
|
|
143 |
|
|
144 |
corec (friend) sfsup :: "nat stream fset \<Rightarrow> nat stream" where
|
|
145 |
"sfsup X = SCons (Sup (fset (fimage shd X))) (sfsup (fimage stl X))"
|
|
146 |
|
|
147 |
text \<open>
|
|
148 |
\noindent
|
|
149 |
In general, the arguments may be any BNF, with the restriction that the target
|
|
150 |
codatatype (@{typ "nat stream"}) may occur only in a live position of the BNF.
|
|
151 |
For this reason, the following operation, on unbounded sets, cannot be
|
|
152 |
registered as a friend:
|
|
153 |
\<close>
|
|
154 |
|
|
155 |
corec ssup :: "nat stream set \<Rightarrow> nat stream" where
|
|
156 |
"ssup X = SCons (Sup (image shd X)) (ssup (image stl X))"
|
|
157 |
|
62739
|
158 |
|
|
159 |
subsection \<open>Nested Corecursion
|
|
160 |
\label{ssec:nested-corecursion}\<close>
|
|
161 |
|
62742
|
162 |
text \<open>
|
|
163 |
The package generally supports arbitrary codatatypes with multiple constructors
|
|
164 |
and nesting through other type constructors (BNFs). Consider the following type
|
|
165 |
of finitely branching Rose trees of potentially infinite depth:
|
|
166 |
\<close>
|
62739
|
167 |
|
62742
|
168 |
codatatype 'a tree =
|
|
169 |
Node (lab: 'a) (sub: "'a tree list")
|
|
170 |
|
|
171 |
text \<open>
|
|
172 |
We first define the pointwise sum of two trees analogously to @{const ssum}:
|
|
173 |
\<close>
|
|
174 |
|
|
175 |
corec (friend) tplus :: "('a :: plus) tree \<Rightarrow> 'a tree \<Rightarrow> 'a tree" where
|
|
176 |
"tplus t u =
|
|
177 |
Node (lab t + lab u) (map (\<lambda>(t', u'). tplus t' u') (zip (sub t) (sub u)))"
|
|
178 |
|
|
179 |
text \<open>
|
|
180 |
\noindent
|
|
181 |
Here, @{const map} is the standard map function on lists, and @{const zip}
|
|
182 |
converts two parallel lists into a list of pairs. The @{const tplus} function is
|
|
183 |
primitively corecursive. Instead of @{text "corec (friend)"}, we could also have
|
|
184 |
used \keyw{primcorec} and @{command friend_of_corec}, as we did for
|
|
185 |
@{const ssum}.
|
|
186 |
|
|
187 |
Once @{const tplus} is registered as friendly, we can use it in the corecursive
|
|
188 |
call context:
|
|
189 |
\<close>
|
|
190 |
|
|
191 |
corec (friend) ttimes :: "('a :: {plus,times}) tree \<Rightarrow> 'a tree \<Rightarrow> 'a tree" where
|
|
192 |
"ttimes t u = Node (lab t * lab u)
|
|
193 |
(map (\<lambda>(t', u'). tplus (ttimes t u') (ttimes t' u)) (zip (sub t) (sub u)))"
|
|
194 |
|
|
195 |
|
|
196 |
subsection \<open>Mixed Recursion--Corecursion
|
|
197 |
\label{ssec:mixed-recursion-corecursion}\<close>
|
|
198 |
|
|
199 |
text \<open>
|
|
200 |
It is often convenient to let a corecursive function perform some finite
|
|
201 |
computation before producing a constructor. With mixed recursion--corecursion, a
|
|
202 |
finite number of unguarded recursive calls perform this calculation before
|
|
203 |
reaching a guarded corecursive call.
|
|
204 |
|
|
205 |
Intuitively, the unguarded recursive call can be unfolded to arbitrary finite
|
|
206 |
depth, ultimately yielding a purely corecursive definition. An example is the
|
|
207 |
@{term primes} function from Di Gianantonio and Miculan
|
|
208 |
\cite{di-gianantonio-miculan-2003}:
|
|
209 |
\<close>
|
|
210 |
|
|
211 |
corecursive primes :: "nat \<Rightarrow> nat \<Rightarrow> nat stream" where
|
|
212 |
"primes m n =
|
|
213 |
(if (m = 0 \<and> n > 1) \<or> coprime m n then
|
|
214 |
SCons n (primes (m * n) (n + 1))
|
|
215 |
else
|
|
216 |
primes m (n + 1))"
|
|
217 |
apply (relation "measure (\<lambda>(m, n).
|
|
218 |
if n = 0 then 1 else if coprime m n then 0 else m - n mod m)")
|
|
219 |
apply (auto simp: mod_Suc intro: Suc_lessI)
|
|
220 |
apply (metis One_nat_def coprime_Suc_nat gcd.commute gcd_red_nat)
|
|
221 |
by (metis diff_less_mono2 lessI mod_less_divisor)
|
|
222 |
|
|
223 |
text \<open>
|
|
224 |
\noindent
|
|
225 |
The @{command corecursive} command is a variant of @{command corec} that allows
|
|
226 |
us to specify a termination argument for any unguarded self-call.
|
|
227 |
|
|
228 |
When called with @{term "m = 1"} and @{term "n = 2"}, the @{const primes}
|
|
229 |
function computes the stream of prime numbers. The unguarded call in the
|
|
230 |
@{text else} branch increments @{term n} until it is coprime to the first
|
|
231 |
argument @{term m} (i.e., the greatest common divisor of @{term m} and
|
|
232 |
@{term n} is @{term 1}).
|
|
233 |
|
|
234 |
For any positive integers @{term m} and @{term n}, the numbers @{term m} and
|
|
235 |
@{term "m * n + 1"} are coprime, yielding an upper bound on the number of times
|
|
236 |
@{term n} is increased. Hence, the function will take the @{text else} branch at
|
|
237 |
most finitely often before taking the then branch and producing one constructor.
|
|
238 |
There is a slight complication when @{term "m = 0 \<and> n > 1"}: Without the first
|
|
239 |
disjunct in the @{text "if"} condition, the function could stall. (This corner
|
|
240 |
case was overlooked in the original example \cite{di-gianantonio-miculan-2003}.)
|
|
241 |
|
|
242 |
In the following example, which defines the stream of Catalan numbers,
|
|
243 |
termination is discharged automatically using @{text lexicographic_order}:
|
|
244 |
\<close>
|
|
245 |
|
|
246 |
corec catalan :: "nat \<Rightarrow> nat stream" where
|
|
247 |
"catalan n =
|
|
248 |
(if n > 0 then ssum (catalan (n - 1)) (SCons 0 (catalan (n + 1)))
|
|
249 |
else SCons 1 (catalan 1))"
|
|
250 |
|
|
251 |
text \<open>
|
|
252 |
A more elaborate case study, revolving around the filter function on lazy lists,
|
|
253 |
is presented in @{file "~~/src/HOL/Corec_Examples/LFilter.thy"}.
|
|
254 |
\<close>
|
|
255 |
|
|
256 |
|
|
257 |
subsection \<open>Self-Friendship
|
|
258 |
\label{ssec:self-friendship}\<close>
|
|
259 |
|
|
260 |
text \<open>
|
|
261 |
Paradoxically, the package allows us to simultaneously define a function and use
|
|
262 |
it as its own friend, as in the following definition of a ``skewed product'':
|
|
263 |
\<close>
|
|
264 |
|
|
265 |
corec (friend)
|
|
266 |
sskew :: "('a :: {plus,times}) stream \<Rightarrow> 'a stream \<Rightarrow> 'a stream"
|
|
267 |
where
|
|
268 |
"sskew xs ys =
|
|
269 |
SCons (shd xs * shd ys) (sskew (sskew xs (stl ys)) (sskew (stl xs) ys))"
|
|
270 |
|
|
271 |
text \<open>
|
|
272 |
\noindent
|
|
273 |
Such definitions, with nested self-calls on the right-hand side, cannot be
|
|
274 |
separated into a @{command corec} part and a @{command friend_of_corec} part.
|
|
275 |
\<close>
|
62739
|
276 |
|
|
277 |
|
|
278 |
subsection \<open>Coinduction
|
|
279 |
\label{ssec:coinduction}\<close>
|
|
280 |
|
62742
|
281 |
text \<open>
|
|
282 |
Once a corecursive specification has been accepted, we normally want to reason
|
|
283 |
about it. The @{text codatatype} command generates a structural coinduction
|
|
284 |
principle that matches primitively corecursive functions. For nonprimitive
|
|
285 |
specifications, our package provides the more advanced proof principle of
|
|
286 |
\emph{coinduction up to congruence}---or simply \emph{coinduction up-to}.
|
|
287 |
|
|
288 |
The structural coinduction principle for @{typ "'a stream"}, called
|
|
289 |
@{thm [source] stream.coinduct}, is as follows:
|
|
290 |
%
|
|
291 |
\[@{thm stream.coinduct[no_vars]}\]
|
|
292 |
%
|
|
293 |
Coinduction allows us to prove an equality @{text "l = r"} on streams by
|
|
294 |
providing a relation @{text R} that relates @{text l} and @{text r} (first
|
|
295 |
premise) and that constitutes a bisimulation (second premise). Streams that are
|
|
296 |
related by a bisimulation cannot be distinguished by taking observations (via
|
|
297 |
the selectors @{const shd} and @{const stl}); hence they must be equal.
|
|
298 |
|
|
299 |
The coinduction up-to principle after registering @{const sskew} as friendly is
|
|
300 |
available as @{thm [source] sskew.coinduct} or
|
|
301 |
@{thm [source] stream.coinduct_upto(2)}:
|
|
302 |
%
|
|
303 |
\[@{thm sfsup.coinduct[no_vars]}\]
|
|
304 |
%
|
|
305 |
This rule is almost identical to structural coinduction, except that the
|
|
306 |
corecursive application of @{term R} is replaced by
|
|
307 |
@{term "stream.v5.congclp R"}. The @{const stream.v5.congclp} predicate is
|
|
308 |
equipped with the following introduction rules:
|
|
309 |
\<close>
|
|
310 |
|
|
311 |
(* FIXME:
|
|
312 |
thm
|
|
313 |
sskew.cong_base
|
|
314 |
sskew.cong_refl
|
|
315 |
sskew.cong_intros
|
|
316 |
|
|
317 |
thm stream.coinduct_upto(2)
|
|
318 |
sskew.coinduct
|
|
319 |
|
|
320 |
thm stream.cong_intros
|
|
321 |
thm sfsup.cong_intros
|
|
322 |
*)
|
|
323 |
|
62739
|
324 |
|
|
325 |
subsection \<open>Uniqueness Reasoning
|
|
326 |
\label{ssec:uniqueness-reasoning}\<close>
|
|
327 |
|
62742
|
328 |
text \<open>
|
|
329 |
...
|
|
330 |
\<close>
|
|
331 |
|
62739
|
332 |
|
|
333 |
section \<open>Command Syntax
|
|
334 |
\label{sec:command-syntax}\<close>
|
|
335 |
|
62742
|
336 |
text \<open>
|
|
337 |
...
|
|
338 |
\<close>
|
62739
|
339 |
|
62742
|
340 |
|
|
341 |
subsection \<open>\keyw{corec} and \keyw{corecursive}
|
62739
|
342 |
\label{ssec:corec-and-corecursive}\<close>
|
|
343 |
|
62742
|
344 |
text \<open>
|
|
345 |
...
|
|
346 |
\<close>
|
|
347 |
|
62739
|
348 |
|
62742
|
349 |
subsection \<open>\keyw{friend_of_corec}
|
62739
|
350 |
\label{ssec:friend-of-corec}\<close>
|
|
351 |
|
62742
|
352 |
text \<open>
|
|
353 |
...
|
|
354 |
\<close>
|
62739
|
355 |
|
62742
|
356 |
|
|
357 |
subsection \<open>\keyw{coinduction_upto}
|
62739
|
358 |
\label{ssec:coinduction-upto}\<close>
|
|
359 |
|
62742
|
360 |
text \<open>
|
|
361 |
...
|
|
362 |
\<close>
|
|
363 |
|
62739
|
364 |
|
|
365 |
section \<open>Generated Theorems
|
|
366 |
\label{sec:generated-theorems}\<close>
|
|
367 |
|
62742
|
368 |
text \<open>
|
|
369 |
...
|
|
370 |
\<close>
|
62739
|
371 |
|
62742
|
372 |
|
|
373 |
subsection \<open>\keyw{corec} and \keyw{corecursive}
|
62739
|
374 |
\label{ssec:corec-and-corecursive}\<close>
|
|
375 |
|
62742
|
376 |
text \<open>
|
|
377 |
...
|
|
378 |
\<close>
|
|
379 |
|
62739
|
380 |
|
62742
|
381 |
subsection \<open>\keyw{friend_of_corec}
|
62739
|
382 |
\label{ssec:friend-of-corec}\<close>
|
|
383 |
|
62742
|
384 |
text \<open>
|
|
385 |
...
|
|
386 |
\<close>
|
62739
|
387 |
|
62742
|
388 |
|
|
389 |
subsection \<open>\keyw{coinduction_upto}
|
62739
|
390 |
\label{ssec:coinduction-upto}\<close>
|
|
391 |
|
62742
|
392 |
text \<open>
|
|
393 |
...
|
|
394 |
\<close>
|
|
395 |
|
62739
|
396 |
|
|
397 |
section \<open>Proof Method
|
|
398 |
\label{sec:proof-method}\<close>
|
|
399 |
|
62742
|
400 |
text \<open>
|
|
401 |
...
|
|
402 |
\<close>
|
62739
|
403 |
|
62742
|
404 |
|
|
405 |
subsection \<open>\textit{corec_unique}
|
62739
|
406 |
\label{ssec:corec-unique}\<close>
|
|
407 |
|
62742
|
408 |
text \<open>
|
|
409 |
...
|
|
410 |
\<close>
|
|
411 |
|
62739
|
412 |
|
|
413 |
section \<open>Known Bugs and Limitations
|
|
414 |
\label{sec:known-bugs-and-limitations}\<close>
|
|
415 |
|
|
416 |
text \<open>
|
|
417 |
This section lists the known bugs and limitations of the corecursion package at
|
|
418 |
the time of this writing.
|
|
419 |
|
|
420 |
\begin{enumerate}
|
|
421 |
\setlength{\itemsep}{0pt}
|
|
422 |
|
|
423 |
\item
|
|
424 |
\emph{TODO.} TODO.
|
|
425 |
|
|
426 |
* no mutual types
|
|
427 |
* limitation on type of friend
|
|
428 |
* unfinished tactics
|
|
429 |
* polymorphism of corecUU_transfer
|
62742
|
430 |
* alternative views
|
62739
|
431 |
|
|
432 |
\end{enumerate}
|
|
433 |
\<close>
|
|
434 |
|
|
435 |
end
|