comparison src/DataStruct.v @ 108:7abf5535baab

STLC interp
author Adam Chlipala <adamc@hcoop.net>
date Mon, 13 Oct 2008 13:20:57 -0400
parents 924d77a177e8
children fe6cfbae86b9
comparison
equal deleted inserted replaced
107:924d77a177e8 108:7abf5535baab
112 end (get ls') 112 end (get ls')
113 end. 113 end.
114 End ilist. 114 End ilist.
115 115
116 Implicit Arguments Nil [A]. 116 Implicit Arguments Nil [A].
117 117 Implicit Arguments First [n].
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. *) 118
119 (** A few examples show how to make use of these definitions. *)
120
121 Check Cons 0 (Cons 1 (Cons 2 Nil)).
122 (** [[
123
124 Cons 0 (Cons 1 (Cons 2 Nil))
125 : ilist nat 3
126 ]] *)
127 Eval simpl in get (Cons 0 (Cons 1 (Cons 2 Nil))) First.
128 (** [[
129
130 = 0
131 : nat
132 ]] *)
133 Eval simpl in get (Cons 0 (Cons 1 (Cons 2 Nil))) (Next First).
134 (** [[
135
136 = 1
137 : nat
138 ]] *)
139 Eval simpl in get (Cons 0 (Cons 1 (Cons 2 Nil))) (Next (Next First)).
140 (** [[
141
142 = 2
143 : nat
144 ]] *)
145
146 (** Our [get] function is also quite easy to reason about. We show how with a short example about an analogue to the list [map] function. *)
119 147
120 Section ilist_map. 148 Section ilist_map.
121 Variables A B : Set. 149 Variables A B : Set.
122 Variable f : A -> B. 150 Variable f : A -> B.
123 151
181 | MFirst _ => fun x _ => x 209 | MFirst _ => fun x _ => x
182 | MNext _ _ mem' => fun _ get_mls' => get_mls' mem' 210 | MNext _ _ mem' => fun _ get_mls' => get_mls' mem'
183 end x (hget mls') 211 end x (hget mls')
184 end. 212 end.
185 End hlist. 213 End hlist.
214
215 Implicit Arguments MNil [A B].
216 Implicit Arguments MCons [A B x ls].
217
218 Implicit Arguments MFirst [A elm ls].
219 Implicit Arguments MNext [A elm x ls].
220
221 (** 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. *)
222
223 Definition someTypes : list Set := nat :: bool :: nil.
224
225 Example someValues : hlist (fun T : Set => T) someTypes :=
226 MCons 5 (MCons true MNil).
227
228 Eval simpl in hget someValues MFirst.
229 (** [[
230
231 = 5
232 : (fun T : Set => T) nat
233 ]] *)
234 Eval simpl in hget someValues (MNext MFirst).
235 (** [[
236
237 = true
238 : (fun T : Set => T) bool
239 ]] *)
240
241 (** We can also build indexed lists of pairs in this way. *)
242
243 Example somePairs : hlist (fun T : Set => T * T)%type someTypes :=
244 MCons (1, 2) (MCons (true, false) MNil).
245
246 (** ** A Lambda Calculus Interpreter *)
247
248 (** Heterogeneous lists are very useful in implementing interpreters for functional programming languages. Using the types and operations we have already defined, it is trivial to write an interpreter for simply-typed lambda calculus. Our interpreter can alternatively be thought of as a denotational semantics.
249
250 We start with an algebraic datatype for types. *)
251
252 Inductive type : Set :=
253 | Unit : type
254 | Arrow : type -> type -> type.
255
256 (** Now we can define a type family for expressions. An [exp ts t] will stand for an expression that has type [t] and whose free variables have types in the list [ts]. We effectively use the de Bruijn variable representation, which we will discuss in more detail in later chapters. Variables are represented as [member] values; that is, a variable is more or less a constructive proof that a particular type is found in the type environment. *)
257
258 Inductive exp : list type -> type -> Set :=
259 | Const : forall ts, exp ts Unit
260
261 | Var : forall ts t, member t ts -> exp ts t
262 | App : forall ts dom ran, exp ts (Arrow dom ran) -> exp ts dom -> exp ts ran
263 | Abs : forall ts dom ran, exp (dom :: ts) ran -> exp ts (Arrow dom ran).
264
265 Implicit Arguments Const [ts].
266
267 (** We write a simple recursive function to translate [type]s into [Set]s. *)
268
269 Fixpoint typeDenote (t : type) : Set :=
270 match t with
271 | Unit => unit
272 | Arrow t1 t2 => typeDenote t1 -> typeDenote t2
273 end.
274
275 (** Now it is straightforward to write an expression interpreter. The type of the function, [expDenote], tells us that we translate expressions into functions from properly-typed environments to final values. An environment for a free variable list [ts] is simply a [hlist typeDenote ts]. That is, for each free variable, the heterogeneous list that is the environment must have a value of the variable's associated type. We use [hget] to implement the [Var] case, and we use [MCons] to extend the environment in the [Abs] case. *)
276
277 Fixpoint expDenote ts t (e : exp ts t) {struct e} : hlist typeDenote ts -> typeDenote t :=
278 match e in exp ts t return hlist typeDenote ts -> typeDenote t with
279 | Const _ => fun _ => tt
280
281 | Var _ _ mem => fun s => hget s mem
282 | App _ _ _ e1 e2 => fun s => (expDenote e1 s) (expDenote e2 s)
283 | Abs _ _ _ e' => fun s => fun x => expDenote e' (MCons x s)
284 end.
285
286 (** Like for previous examples, our interpreter is easy to run with [simpl]. *)
287
288 Eval simpl in expDenote Const MNil.
289 (** [[
290
291 = tt
292 : typeDenote Unit
293 ]] *)
294 Eval simpl in expDenote (Abs (dom := Unit) (Var MFirst)) MNil.
295 (** [[
296
297 = fun x : unit => x
298 : typeDenote (Arrow Unit Unit)
299 ]] *)
300 Eval simpl in expDenote (Abs (dom := Unit)
301 (Abs (dom := Unit) (Var (MNext MFirst)))) MNil.
302 (** [[
303
304 = fun x _ : unit => x
305 : typeDenote (Arrow Unit (Arrow Unit Unit))
306 ]] *)
307 Eval simpl in expDenote (Abs (dom := Unit) (Abs (dom := Unit) (Var MFirst))) MNil.
308 (** [[
309
310 = fun _ x0 : unit => x0
311 : typeDenote (Arrow Unit (Arrow Unit Unit))
312 ]] *)
313 Eval simpl in expDenote (App (Abs (Var MFirst)) Const) MNil.
314 (** [[
315
316 = tt
317 : typeDenote Unit
318 ]] *)
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. *)
321
322