Commit a1f728fa authored by Adam Chlipala's avatar Adam Chlipala

Batch of changes based on proofreader feedback

parent 501370fd
...@@ -41,7 +41,7 @@ Section ilist. ...@@ -41,7 +41,7 @@ Section ilist.
| First : forall n, fin (S n) | First : forall n, fin (S n)
| Next : forall n, fin n -> fin (S n). | Next : forall n, fin n -> fin (S n).
(** An instance of [fin] is essentially a more richly typed copy of the natural numbers. Every element is a [First] iterated through applying [Next] a number of times that indicates which number is being selected. For instance, the three values of type [fin 3] are [First 2], [Next (First 1)], and [Next (Next (First 0))]. (** An instance of [fin] is essentially a more richly typed copy of a prefix of the natural numbers. The type [fin n] is isomorphic to [{m : nat | m < n}]. Every element is a [First] iterated through applying [Next] a number of times that indicates which number is being selected. For instance, the three values of type [fin 3] are [First 2], [Next (First 1)], and [Next (Next (First 0))].
Now it is easy to pick a [Prop]-free type for a selection function. As usual, our first implementation attempt will not convince the type checker, and we will attack the deficiencies one at a time. Now it is easy to pick a [Prop]-free type for a selection function. As usual, our first implementation attempt will not convince the type checker, and we will attack the deficiencies one at a time.
[[ [[
...@@ -55,7 +55,7 @@ Section ilist. ...@@ -55,7 +55,7 @@ Section ilist.
end end
end. end.
]] ]]
%\vspace{-.15in}%We apply the usual wisdom of delaying arguments in [Fixpoint]s so that they may be included in [return] clauses. This still leaves us with a quandary in each of the [match] cases. First, we need to figure out how to take advantage of the contradiction in the [Nil] case. Every [fin] has a type of the form [S n], which cannot unify with the [O] value that we learn for [n] in the [Nil] case. The solution we adopt is another case of [match]-within-[return]. %\vspace{-.15in}%We apply the usual wisdom of delaying arguments in [Fixpoint]s so that they may be included in [return] clauses. This still leaves us with a quandary in each of the [match] cases. First, we need to figure out how to take advantage of the contradiction in the [Nil] case. Every [fin] has a type of the form [S n], which cannot unify with the [O] value that we learn for [n] in the [Nil] case. The solution we adopt is another case of [match]-within-[return], with the [return] clause chosen carefully so that it returns the proper type [A] in case the [fin] index is [O], which we know is true here; and so that it returns an easy-to-inhabit type [unit] in the remaining, impossible cases, which nonetheless appear explicitly in the body of the [match].
[[ [[
Fixpoint get n (ls : ilist n) : fin n -> A := Fixpoint get n (ls : ilist n) : fin n -> A :=
match ls with match ls with
...@@ -200,7 +200,7 @@ Section hlist. ...@@ -200,7 +200,7 @@ Section hlist.
| HNil : hlist nil | HNil : hlist nil
| HCons : forall (x : A) (ls : list A), B x -> hlist ls -> hlist (x :: ls). | HCons : forall (x : A) (ls : list A), B x -> hlist ls -> hlist (x :: ls).
(** We can implement a variant of the last section's [get] function for [hlist]s. To get the dependent typing to work out, we will need to index our element selectors by the types of data that they point to.%\index{Gallina terms!member}% *) (** We can implement a variant of the last section's [get] function for [hlist]s. To get the dependent typing to work out, we will need to index our element selectors (in type family [member]) by the types of data that they point to.%\index{Gallina terms!member}% *)
(* end thide *) (* end thide *)
(* EX: Define an analogue to [get] for [hlist]s. *) (* EX: Define an analogue to [get] for [hlist]s. *)
...@@ -248,7 +248,7 @@ Implicit Arguments HFirst [A elm ls]. ...@@ -248,7 +248,7 @@ Implicit Arguments HFirst [A elm ls].
Implicit Arguments HNext [A elm x ls]. Implicit Arguments HNext [A elm x ls].
(* end thide *) (* end thide *)
(** By putting the parameters [A] and [B] in [Type], we allow some very higher-order uses. For instance, one use of [hlist] is for the simple heterogeneous lists that we referred to earlier. *) (** By putting the parameters [A] and [B] in [Type], we enable fancier kinds of polymorphism than in mainstream functional languages. For instance, one use of [hlist] is for the simple heterogeneous lists that we referred to earlier. *)
Definition someTypes : list Set := nat :: bool :: nil. Definition someTypes : list Set := nat :: bool :: nil.
...@@ -370,7 +370,7 @@ Eval simpl in expDenote (App (Abs (Var HFirst)) Const) HNil. ...@@ -370,7 +370,7 @@ Eval simpl in expDenote (App (Abs (Var HFirst)) Const) HNil.
(** * Recursive Type Definitions *) (** * Recursive Type Definitions *)
(** %\index{recursive type definition}%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 _recursive_ definitions. *) (** %\index{recursive type definition}%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 _recursive_ definitions. Here we will preface type names with the letter [f] to indicate that they are based on explicit recursive _function_ definitions. *)
(* EX: Come up with an alternate [ilist] definition that makes it easier to write [get]. *) (* EX: Come up with an alternate [ilist] definition that makes it easier to write [get]. *)
......
...@@ -180,7 +180,7 @@ Recall that co-recursive definitions have a dual rule: a co-recursive call only ...@@ -180,7 +180,7 @@ Recall that co-recursive definitions have a dual rule: a co-recursive call only
(** * Heterogeneous Lists Revisited *) (** * Heterogeneous Lists Revisited *)
(** One of our example dependent data structures from the last chapter was the heterogeneous list and its associated "cursor" type. The recursive version poses some special challenges related to equality proofs, since it uses such proofs in its definition of [fmember] types. *) (** One of our example dependent data structures from the last chapter (code repeated below) was the heterogeneous list and its associated "cursor" type. The recursive version poses some special challenges related to equality proofs, since it uses such proofs in its definition of [fmember] types. *)
Section fhlist. Section fhlist.
Variable A : Type. Variable A : Type.
...@@ -420,7 +420,7 @@ UIP_refl ...@@ -420,7 +420,7 @@ UIP_refl
: forall (U : Type) (x : U) (p : x = x), p = eq_refl x : forall (U : Type) (x : U) (p : x = x), p = eq_refl x
]] ]]
The theorem %\index{Gallina terms!UIP\_refl}%[UIP_refl] comes from the [Eqdep] module of the standard library. Do the Coq authors know of some clever trick for building such proofs that we have not seen yet? If they do, they did not use it for this proof. Rather, the proof is based on an _axiom_, the term [eq_rect_eq] below. *) The theorem %\index{Gallina terms!UIP\_refl}%[UIP_refl] comes from the [Eqdep] module of the standard library. (Its name uses the acronym "UIP" for "unicity of identity proofs.") Do the Coq authors know of some clever trick for building such proofs that we have not seen yet? If they do, they did not use it for this proof. Rather, the proof is based on an _axiom_, the term [eq_rect_eq] below. *)
(* begin hide *) (* begin hide *)
Import Eq_rect_eq. Import Eq_rect_eq.
...@@ -459,16 +459,15 @@ x = eq_rect p Q x p h ] ...@@ -459,16 +459,15 @@ x = eq_rect p Q x p h ]
(* end thide *) (* end thide *)
(* end hide *) (* end hide *)
Print Streicher_K. Check Streicher_K.
(* end thide *) (* end thide *)
(** %\vspace{-.15in}% [[ (** %\vspace{-.15in}% [[
Streicher_K = Streicher_K
fun U : Type => UIP_refl__Streicher_K U (UIP_refl U)
: forall (U : Type) (x : U) (P : x = x -> Prop), : forall (U : Type) (x : U) (P : x = x -> Prop),
P (eq_refl x) -> forall p : x = x, P p P eq_refl -> forall p : x = x, P p
]] ]]
This is the unfortunately named %\index{axiom K}%"Streicher's axiom K," which says that a predicate on properly typed equality proofs holds of all such proofs if it holds of reflexivity. *) This is the opaquely named %\index{axiom K}%"Streicher's axiom K," which says that a predicate on properly typed equality proofs holds of all such proofs if it holds of reflexivity. *)
End fhlist_map. End fhlist_map.
...@@ -691,7 +690,7 @@ Inductive JMeq (A : Type) (x : A) : forall B : Type, B -> Prop := ...@@ -691,7 +690,7 @@ Inductive JMeq (A : Type) (x : A) : forall B : Type, B -> Prop :=
JMeq_refl : JMeq x x JMeq_refl : JMeq x x
]] ]]
The identifier [JMeq] stands for %\index{John Major equality}%"John Major equality," a name coined by Conor McBride%~\cite{JMeq}% as a sort of pun about British politics. The definition [JMeq] starts out looking a lot like the definition of [eq]. The crucial difference is that we may use [JMeq] _on arguments of different types_. For instance, a lemma that we failed to establish before is trivial with [JMeq]. It makes for prettier theorem statements to define some syntactic shorthand first. *) The identifier [JMeq] stands for %\index{John Major equality}%"John Major equality," a name coined by Conor McBride%~\cite{JMeq}% as an inside joke about British politics. The definition [JMeq] starts out looking a lot like the definition of [eq]. The crucial difference is that we may use [JMeq] _on arguments of different types_. For instance, a lemma that we failed to establish before is trivial with [JMeq]. It makes for prettier theorem statements to define some syntactic shorthand first. *)
Infix "==" := JMeq (at level 70, no associativity). Infix "==" := JMeq (at level 70, no associativity).
...@@ -722,7 +721,7 @@ JMeq_eq ...@@ -722,7 +721,7 @@ JMeq_eq
: forall (A : Type) (x y : A), x == y -> x = y : forall (A : Type) (x y : A), x == y -> x = y
]] ]]
It may be surprising that we cannot prove that heterogeneous equality implies normal equality. The difficulties are the same kind we have seen so far, based on limitations of [match] annotations. It may be surprising that we cannot prove that heterogeneous equality implies normal equality. The difficulties are the same kind we have seen so far, based on limitations of [match] annotations. The [JMeq_eq] axiom has been proved on paper to be consistent, but asserting it may still be considered to complicate the logic we work in, so there is some motivation for avoiding it.
We can redo our [fhapp] associativity proof based around [JMeq]. *) We can redo our [fhapp] associativity proof based around [JMeq]. *)
...@@ -862,7 +861,7 @@ Theorem out_of_luck : forall n m : nat, ...@@ -862,7 +861,7 @@ Theorem out_of_luck : forall n m : nat,
-> S n == S m. -> S n == S m.
intros n m H. intros n m H.
(** Applying [JMeq_ind_r] is easy, as the %\index{tactics!pattern}%[pattern] tactic will transform the goal into an application of an appropriate [fun] to a term that we want to abstract. *) (** Applying [JMeq_ind_r] is easy, as the %\index{tactics!pattern}%[pattern] tactic will transform the goal into an application of an appropriate [fun] to a term that we want to abstract. (In general, [pattern] abstracts over a term by introducing a new anonymous function taking that term as argument.) *)
pattern n. pattern n.
(** %\vspace{-.15in}%[[ (** %\vspace{-.15in}%[[
......
This diff is collapsed.
...@@ -30,7 +30,7 @@ Set Implicit Arguments. ...@@ -30,7 +30,7 @@ Set Implicit Arguments.
Thus, to begin, we must define a syntactic representation of some class of datatypes. In this chapter, our running example will have to do with basic algebraic datatypes, of the kind found in ML and Haskell, but without additional bells and whistles like type parameters and mutually recursive definitions. Thus, to begin, we must define a syntactic representation of some class of datatypes. In this chapter, our running example will have to do with basic algebraic datatypes, of the kind found in ML and Haskell, but without additional bells and whistles like type parameters and mutually recursive definitions.
The first step is to define a representation for constructors of our datatypes. *) The first step is to define a representation for constructors of our datatypes. We use the [Record] command as a shorthand for defining an inductive type with a single constructor, plus projection functions for pulling out any of the named arguments to that constructor. *)
(* EX: Define a reified representation of simple algebraic datatypes. *) (* EX: Define a reified representation of simple algebraic datatypes. *)
...@@ -42,7 +42,7 @@ Record constructor : Type := Con { ...@@ -42,7 +42,7 @@ Record constructor : Type := Con {
(** The idea is that a constructor represented as [Con T n] has [n] arguments of the type that we are defining. Additionally, all of the other, non-recursive arguments can be encoded in the type [T]. When there are no non-recursive arguments, [T] can be [unit]. When there are two non-recursive arguments, of types [A] and [B], [T] can be [A * B]. We can generalize to any number of arguments via tupling. (** The idea is that a constructor represented as [Con T n] has [n] arguments of the type that we are defining. Additionally, all of the other, non-recursive arguments can be encoded in the type [T]. When there are no non-recursive arguments, [T] can be [unit]. When there are two non-recursive arguments, of types [A] and [B], [T] can be [A * B]. We can generalize to any number of arguments via tupling.
With this definition, it as easy to define a datatype representation in terms of lists of constructors. *) With this definition, it is easy to define a datatype representation in terms of lists of constructors. The intended meaning is that the datatype came from an inductive definition including exactly the constructors in the list. *)
Definition datatype := list constructor. Definition datatype := list constructor.
......
...@@ -106,7 +106,7 @@ It is not clear what to write for the [Nil] case, so we are stuck before we even ...@@ -106,7 +106,7 @@ It is not clear what to write for the [Nil] case, so we are stuck before we even
Error: Non exhaustive pattern-matching: no clause found for pattern Nil Error: Non exhaustive pattern-matching: no clause found for pattern Nil
>> >>
Unlike in ML, we cannot use inexhaustive pattern matching, because there is no conception of a <<Match>> exception to be thrown. In fact, recent versions of Coq _do_ allow this, by implicit translation to a [match] that considers all constructors. It is educational to discover such an encoding for ourselves. We might try using an [in] clause somehow. Unlike in ML, we cannot use inexhaustive pattern matching, because there is no conception of a <<Match>> exception to be thrown. In fact, recent versions of Coq _do_ allow this, by implicit translation to a [match] that considers all constructors; the error message above was generated by an older Coq version. It is educational to discover for ourselves the encoding that the most recent Coq versions use. We might try using an [in] clause somehow.
[[ [[
Definition hd n (ls : ilist (S n)) : A := Definition hd n (ls : ilist (S n)) : A :=
...@@ -158,15 +158,15 @@ When exactly will Coq accept a dependent pattern match as well-typed? Some othe ...@@ -158,15 +158,15 @@ When exactly will Coq accept a dependent pattern match as well-typed? Some othe
We come now to the one rule of dependent pattern matching in Coq. A general dependent pattern match assumes this form (with unnecessary parentheses included to make the syntax easier to parse): We come now to the one rule of dependent pattern matching in Coq. A general dependent pattern match assumes this form (with unnecessary parentheses included to make the syntax easier to parse):
[[ [[
match E in (T x1 ... xn) as y return U with match E as y in (T x1 ... xn) return U with
| C z1 ... zm => B | C z1 ... zm => B
| ... | ...
end end
]] ]]
The discriminee is a term [E], a value in some inductive type family [T], which takes [n] arguments. An %\index{in clause}%[in] clause binds an explicit name [xi] for the [i]th argument passed to [T] in the type of [E]. An %\index{as clause}%[as] clause binds the name [y] to refer to the discriminee [E]. The discriminee is a term [E], a value in some inductive type family [T], which takes [n] arguments. An %\index{as clause}%[as] clause binds the name [y] to refer to the discriminee [E]. An %\index{in clause}%[in] clause binds an explicit name [xi] for the [i]th argument passed to [T] in the type of [E].
We bind these new variables [xi] and [y] so that they may be referred to in [U], a type given in the %\index{return clause}%[return] clause. The overall type of the [match] will be [U], with [E] substituted for [y], and with each [xi] substituted by the actual argument appearing in that position within [E]'s type. We bind these new variables [y] and [xi] so that they may be referred to in [U], a type given in the %\index{return clause}%[return] clause. The overall type of the [match] will be [U], with [E] substituted for [y], and with each [xi] substituted by the actual argument appearing in that position within [E]'s type.
In general, each case of a [match] may have a pattern built up in several layers from the constructors of various inductive type families. To keep this exposition simple, we will focus on patterns that are just single applications of inductive type constructors to lists of variables. Coq actually compiles the more general kind of pattern matching into this more restricted kind automatically, so understanding the typing of [match] requires understanding the typing of [match]es lowered to match one constructor at a time. In general, each case of a [match] may have a pattern built up in several layers from the constructors of various inductive type families. To keep this exposition simple, we will focus on patterns that are just single applications of inductive type constructors to lists of variables. Coq actually compiles the more general kind of pattern matching into this more restricted kind automatically, so understanding the typing of [match] requires understanding the typing of [match]es lowered to match one constructor at a time.
...@@ -378,13 +378,13 @@ User error: e1 is used in hypothesis e ...@@ -378,13 +378,13 @@ User error: e1 is used in hypothesis e
Coq gives us another cryptic error message. Like so many others, this one basically means that Coq is not able to build some proof about dependent types. It is hard to generate helpful and specific error messages for problems like this, since that would require some kind of understanding of the dependency structure of a piece of code. We will encounter many examples of case-specific tricks for recovering from errors like this one. Coq gives us another cryptic error message. Like so many others, this one basically means that Coq is not able to build some proof about dependent types. It is hard to generate helpful and specific error messages for problems like this, since that would require some kind of understanding of the dependency structure of a piece of code. We will encounter many examples of case-specific tricks for recovering from errors like this one.
For our current proof, we can use a tactic [dep_destruct]%\index{tactics!dep\_destruct}% defined in the book's [CpdtTactics] module. General elimination/inversion of dependently typed hypotheses is undecidable, since it must be implemented with [match] expressions that have the restriction on [in] clauses that we have already discussed. The tactic [dep_destruct] makes a best effort to handle some common cases, relying upon the more primitive %\index{tactics!dependent destruction}%[dependent destruction] tactic that comes with Coq. In a future chapter, we will learn about the explicit manipulation of equality proofs that is behind [dep_destruct]'s implementation in Ltac, but for now, we treat it as a useful black box. (In Chapter 12, we will also see how [dependent destruction] forces us to make a larger philosophical commitment about our logic than we might like, and we will see some workarounds.) *) For our current proof, we can use a tactic [dep_destruct]%\index{tactics!dep\_destruct}% defined in the book's [CpdtTactics] module. General elimination/inversion of dependently typed hypotheses is undecidable, as witnessed by a simple reduction to the known-undecidable problem of higher-order unification, which has come up a few times already. The tactic [dep_destruct] makes a best effort to handle some common cases, relying upon the more primitive %\index{tactics!dependent destruction}%[dependent destruction] tactic that comes with Coq. In a future chapter, we will learn about the explicit manipulation of equality proofs that is behind [dependent destruction]'s implementation, but for now, we treat it as a useful black box. (In Chapter 12, we will also see how [dependent destruction] forces us to make a larger philosophical commitment about our logic than we might like, and we will see some workarounds.) *)
dep_destruct (cfold e1). dep_destruct (cfold e1).
(** This successfully breaks the subgoal into 5 new subgoals, one for each constructor of [exp] that could produce an [exp Nat]. Note that [dep_destruct] is successful in ruling out the other cases automatically, in effect automating some of the work that we have done manually in implementing functions like [hd] and [pairOut]. (** This successfully breaks the subgoal into 5 new subgoals, one for each constructor of [exp] that could produce an [exp Nat]. Note that [dep_destruct] is successful in ruling out the other cases automatically, in effect automating some of the work that we have done manually in implementing functions like [hd] and [pairOut].
This is the only new trick we need to learn to complete the proof. We can back up and give a short, automated proof. *) This is the only new trick we need to learn to complete the proof. We can back up and give a short, automated proof (which again is safe to skip and uses Ltac features not introduced yet). *)
Restart. Restart.
...@@ -786,7 +786,7 @@ Section star. ...@@ -786,7 +786,7 @@ Section star.
-> star (s1 ++ s2). -> star (s1 ++ s2).
End star. End star.
(** Now we can make our first attempt at defining a [regexp] type that is indexed by predicates on strings. Here is a reasonable-looking definition that is restricted to constant characters and concatenation. We use the constructor [String], which is the analogue of list cons for the type [string], where [""] is like list nil. (** Now we can make our first attempt at defining a [regexp] type that is indexed by predicates on strings, such that the index of a [regexp] tells us which language (string predicate) it recognizes. Here is a reasonable-looking definition that is restricted to constant characters and concatenation. We use the constructor [String], which is the analogue of list cons for the type [string], where [""] is like list nil.
[[ [[
Inductive regexp : (string -> Prop) -> Set := Inductive regexp : (string -> Prop) -> Set :=
| Char : forall ch : ascii, | Char : forall ch : ascii,
...@@ -1115,23 +1115,19 @@ Section dec_star. ...@@ -1115,23 +1115,19 @@ Section dec_star.
-> ~ P (substring n (S l') s) -> ~ P (substring n (S l') s)
\/ ~ P' (substring (n + S l') (length s - (n + S l')) s)}. \/ ~ P' (substring (n + S l') (length s - (n + S l')) s)}.
refine (fix F (l : nat) : {exists l', S l' <= l refine (fix F (l : nat) : {exists l', S l' <= l
/\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)} /\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)}
+ {forall l', S l' <= l + {forall l', S l' <= l
-> ~ P (substring n (S l') s) -> ~ P (substring n (S l') s)
\/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} := \/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} :=
match l return {exists l', S l' <= l match l with
/\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)} | O => _
+ {forall l', S l' <= l | S l' =>
-> ~ P (substring n (S l') s) (P_dec (substring n (S l') s) && P'_dec (n' := n + S l') _)
\/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} with || F l'
| O => _ end); clear F; crush; eauto 7;
| S l' => match goal with
(P_dec (substring n (S l') s) && P'_dec (n' := n + S l') _) | [ H : ?X <= S ?Y |- _ ] => destruct (eq_nat_dec X (S Y)); crush
|| F l' end.
end); clear F; crush; eauto 7;
match goal with
| [ H : ?X <= S ?Y |- _ ] => destruct (eq_nat_dec X (S Y)); crush
end.
Defined. Defined.
End dec_star''. End dec_star''.
......
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
<webMaster>adam@chlipala.net</webMaster> <webMaster>adam@chlipala.net</webMaster>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> <docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<title>Batch of changes based on proofreader feedback</title>
<pubDate>Fri, 30 Nov 2012 11:57:14 EST</pubDate>
<link>http://adam.chlipala.net/cpdt/</link>
<author>adamc@csail.mit.edu</author>
<description>Thanks to everyone who is helping with the final proofreading!</description>
</item>
<item> <item>
<title>Batch of changes based on proofreader feedback</title> <title>Batch of changes based on proofreader feedback</title>
<pubDate>Sun, 11 Nov 2012 18:16:46 EST</pubDate> <pubDate>Sun, 11 Nov 2012 18:16:46 EST</pubDate>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment