Mercurial > cpdt > repo
comparison src/DataStruct.v @ 109:fe6cfbae86b9
Recursive type definitions
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Mon, 13 Oct 2008 14:04:39 -0400 |
parents | 7abf5535baab |
children | 4627b9caac8b |
comparison
equal
deleted
inserted
replaced
108:7abf5535baab | 109:fe6cfbae86b9 |
---|---|
318 ]] *) | 318 ]] *) |
319 | 319 |
320 (** We are starting to develop the tools behind dependent typing's amazing advantage over alternative approaches in several important areas. Here, we have implemented complete syntax, typing rules, and evaluation semantics for simply-typed lambda calculus without even needing to define a syntactic substitution operation. We did it all without a single line of proof, and our implementation is manifestly executable. In a later chapter, we will meet other, more common approaches to language formalization. Such approaches often state and prove explicit theorems about type safety of languages. In the above example, we got type safety, termination, and other meta-theorems for free, by reduction to CIC, which we know has those properties. *) | 320 (** We are starting to develop the tools behind dependent typing's amazing advantage over alternative approaches in several important areas. Here, we have implemented complete syntax, typing rules, and evaluation semantics for simply-typed lambda calculus without even needing to define a syntactic substitution operation. We did it all without a single line of proof, and our implementation is manifestly executable. In a later chapter, we will meet other, more common approaches to language formalization. Such approaches often state and prove explicit theorems about type safety of languages. In the above example, we got type safety, termination, and other meta-theorems for free, by reduction to CIC, which we know has those properties. *) |
321 | 321 |
322 | 322 |
323 (** * Recursive Type Definitions *) | |
324 | |
325 (** There is another style of datatype definition that leads to much simpler definitions of the [get] and [hget] definitions above. Because Coq supports "type-level computation," we can redo our inductive definitions as %\textit{%#<i>#recursive#</i>#%}% definitions. *) | |
326 | |
327 Section filist. | |
328 Variable A : Set. | |
329 | |
330 Fixpoint filist (n : nat) : Set := | |
331 match n with | |
332 | O => unit | |
333 | S n' => A * filist n' | |
334 end%type. | |
335 | |
336 (** We say that a list of length 0 has no contents, and a list of length [S n'] is a pair of a data value and a list of length [n']. *) | |
337 | |
338 Fixpoint findex (n : nat) : Set := | |
339 match n with | |
340 | O => Empty_set | |
341 | S n' => option (findex n') | |
342 end. | |
343 | |
344 (** We express that there are no index values when [n = O], by defining such indices as type [Empty_set]; and we express that, at [n = S n'], there is a choice between picking the first element of the list (represented as [None]) or choosing a later element (represented by [Some idx], where [idx] is an index into the list tail). *) | |
345 | |
346 Fixpoint fget (n : nat) : filist n -> findex n -> A := | |
347 match n return filist n -> findex n -> A with | |
348 | O => fun _ idx => match idx with end | |
349 | S n' => fun ls idx => | |
350 match idx with | |
351 | None => fst ls | |
352 | Some idx' => fget n' (snd ls) idx' | |
353 end | |
354 end. | |
355 | |
356 (** Our new [get] implementation needs only one dependent [match], which just copies the stated return type of the function. Our choices of data structure implementations lead to just the right typing behavior for this new definition to work out. *) | |
357 End filist. | |
358 | |
359 (** Heterogeneous lists are a little trickier to define with recursion, but we then reap similar benefits in simplicity of use. *) | |
360 | |
361 Section fhlist. | |
362 Variable A : Type. | |
363 Variable B : A -> Type. | |
364 | |
365 Fixpoint fhlist (ls : list A) : Type := | |
366 match ls with | |
367 | nil => unit | |
368 | x :: ls' => B x * fhlist ls' | |
369 end%type. | |
370 | |
371 (** The definition of [fhlist] follows the definition of [filist], with the added wrinkle of dependently-typed data elements. *) | |
372 | |
373 Variable elm : A. | |
374 | |
375 Fixpoint fmember (ls : list A) : Type := | |
376 match ls with | |
377 | nil => Empty_set | |
378 | x :: ls' => (x = elm) + fmember ls' | |
379 end%type. | |
380 | |
381 (** The definition of [fmember] follows the definition of [findex]. Empty lists have no members, and member types for nonempty lists are built by adding one new option to the type of members of the list tail. While for [index] we needed no new information associated with the option that we add, here we need to know that the head of the list equals the element we are searching for. We express that with a sum type whose left branch is the appropriate equality proposition. Since we define [fmember] to live in [Type], we can insert [Prop] types as needed, because [Prop] is a subtype of [Type]. | |
382 | |
383 We know all of the tricks needed to write a first attempt at a [get] function for [fhlist]s. | |
384 | |
385 [[ | |
386 | |
387 Fixpoint fhget (ls : list A) : fhlist ls -> fmember ls -> B elm := | |
388 match ls return fhlist ls -> fmember ls -> B elm with | |
389 | nil => fun _ idx => match idx with end | |
390 | _ :: ls' => fun mls idx => | |
391 match idx with | |
392 | inl _ => fst mls | |
393 | inr idx' => fhget ls' (snd mls) idx' | |
394 end | |
395 end. | |
396 | |
397 Only one problem remains. The expression [fst mls] is not known to have the proper type. To demonstrate that it does, we need to use the proof available in the [inl] case of the inner [match]. *) | |
398 | |
399 Fixpoint fhget (ls : list A) : fhlist ls -> fmember ls -> B elm := | |
400 match ls return fhlist ls -> fmember ls -> B elm with | |
401 | nil => fun _ idx => match idx with end | |
402 | _ :: ls' => fun mls idx => | |
403 match idx with | |
404 | inl pf => match pf with | |
405 | refl_equal => fst mls | |
406 end | |
407 | inr idx' => fhget ls' (snd mls) idx' | |
408 end | |
409 end. | |
410 | |
411 (** By pattern-matching on the equality proof [pf], we make that equality known to the type-checker. Exactly why this works can be seen by studying the definition of equality. *) | |
412 | |
413 Print eq. | |
414 (** [[ | |
415 | |
416 Inductive eq (A : Type) (x : A) : A -> Prop := refl_equal : x = x | |
417 ]] | |
418 | |
419 In a proposition [x = y], we see that [x] is a parameter and [y] is a regular argument. The type of the constructor [refl_equal] shows that [y] can only ever be instantiated to [x]. Thus, within a pattern-match with [refl_equal], occurrences of [y] can be replaced with occurrences of [x] for typing purposes. All examples of similar dependent pattern matching that we have seen before require explicit annotations, but Coq implements a special case of annotation inference for matches on equality proofs. *) | |
420 End fhlist. |