comparison src/DataStruct.v @ 107:924d77a177e8

hlist and hget
author Adam Chlipala <adamc@hcoop.net>
date Mon, 13 Oct 2008 12:35:48 -0400
parents 1d2746eae1a6
children 7abf5535baab
comparison
equal deleted inserted replaced
106:1d2746eae1a6 107:924d77a177e8
113 end. 113 end.
114 End ilist. 114 End ilist.
115 115
116 Implicit Arguments Nil [A]. 116 Implicit Arguments Nil [A].
117 117
118 (** Our [get] function is quite easy to reason about. We show how with a short example about an analogue to the list [map] function. *)
119
118 Section ilist_map. 120 Section ilist_map.
119 Variables A B : Set. 121 Variables A B : Set.
120 Variable f : A -> B. 122 Variable f : A -> B.
121 123
122 Fixpoint imap n (ls : ilist A n) {struct ls} : ilist B n := 124 Fixpoint imap n (ls : ilist A n) {struct ls} : ilist B n :=
123 match ls in ilist _ n return ilist B n with 125 match ls in ilist _ n return ilist B n with
124 | Nil => Nil 126 | Nil => Nil
125 | Cons _ x ls' => Cons (f x) (imap ls') 127 | Cons _ x ls' => Cons (f x) (imap ls')
126 end. 128 end.
127 129
128 Theorem get_imap : forall n (ls : ilist A n) (idx : index n), 130 (** It is easy to prove that [get] "distributes over" [imap] calls. The only tricky bit is remembering to use the [dep_destruct] tactic in place of plain [destruct] when faced with a baffling tactic error message. *)
131
132 Theorem get_imap : forall n (idx : index n) (ls : ilist A n),
129 get (imap ls) idx = f (get ls idx). 133 get (imap ls) idx = f (get ls idx).
130 induction ls; crush; 134 induction ls; dep_destruct idx; crush.
131 match goal with
132 | [ |- context[match ?IDX with First _ => _ | Next _ _ => _ end] ] =>
133 dep_destruct IDX; crush
134 end.
135 Qed. 135 Qed.
136 End ilist_map. 136 End ilist_map.
137
138
139 (** * Heterogeneous Lists *)
140
141 (** Programmers who move to statically-typed functional languages from "scripting languages" often complain about the requirement that every element of a list have the same type. With fancy type systems, we can partially lift this requirement. We can index a list type with a "type-level" list that explains what type each element of the list should have. This has been done in a variety of ways in Haskell using type classes, and it we can do it much more cleanly and directly in Coq. *)
142
143 Section hlist.
144 Variable A : Type.
145 Variable B : A -> Type.
146
147 (** We parameterize our heterogeneous lists by a type [A] and an [A]-indexed type [B]. *)
148
149 Inductive hlist : list A -> Type :=
150 | MNil : hlist nil
151 | MCons : forall (x : A) (ls : list A), B x -> hlist ls -> hlist (x :: ls).
152
153 (** 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. *)
154
155 Variable elm : A.
156
157 Inductive member : list A -> Type :=
158 | MFirst : forall ls, member (elm :: ls)
159 | MNext : forall x ls, member ls -> member (x :: ls).
160
161 (** Because the element [elm] that we are "searching for" in a list does not change across the constructors of [member], we simplify our definitions by making [elm] a local variable. In the definition of [member], we say that [elm] is found in any list that begins with [elm], and, if removing the first element of a list leaves [elm] present, then [elm] is present in the original list, too. The form looks much like a predicate for list membership, but we purposely define [member] in [Type] so that we may decompose its values to guide computations.
162
163 We can use [member] to adapt our definition of [get] to [hlists]. The same basic [match] tricks apply. In the [MCons] case, we form a two-element convoy, passing both the data element [x] and the recursor for the sublist [mls'] to the result of the inner [match]. We did not need to do that in [get]'s definition because the types of list elements were not dependent there. *)
164
165 Fixpoint hget ls (mls : hlist ls) {struct mls} : member ls -> B elm :=
166 match mls in hlist ls return member ls -> B elm with
167 | MNil => fun mem =>
168 match mem in member ls' return (match ls' with
169 | nil => B elm
170 | _ :: _ => unit
171 end) with
172 | MFirst _ => tt
173 | MNext _ _ _ => tt
174 end
175 | MCons _ _ x mls' => fun mem =>
176 match mem in member ls' return (match ls' with
177 | nil => Empty_set
178 | x' :: ls'' =>
179 B x' -> (member ls'' -> B elm) -> B elm
180 end) with
181 | MFirst _ => fun x _ => x
182 | MNext _ _ mem' => fun _ get_mls' => get_mls' mem'
183 end x (hget mls')
184 end.
185 End hlist.