comparison src/ProgLang.v @ 510:fd6ec9b2dccb

Finished last pass through the book before beginning the MIT Press editorial process
author Adam Chlipala <adam@chlipala.net>
date Wed, 13 Feb 2013 10:22:18 -0500
parents 6252dd4540a9
children ed829eaa91b2
comparison
equal deleted inserted replaced
509:21079e42b773 510:fd6ec9b2dccb
297 termDenote (unlet e s) s1 297 termDenote (unlet e s) s1
298 = termDenote e (hmap (fun t' (e' : term G' t') => termDenote e' s1) s). 298 = termDenote e (hmap (fun t' (e' : term G' t') => termDenote e' s1) s).
299 induction e; pl. 299 induction e; pl.
300 Qed. 300 Qed.
301 301
302 (** The lemma statement is a mouthful, with all its details of typing contexts and substitutions. It is usually prudent to state a final theorem in as simple a way as possible, to help your readers believe that you have proved what they expect. We do that here for the simple case of terms with empty typing contexts. *) 302 (** The lemma statement is a mouthful, with all its details of typing contexts and substitutions. It is usually prudent to state a final theorem in as simple a way as possible, to help your readers believe that you have proved what they expect. We follow that advice here for the simple case of terms with empty typing contexts. *)
303 303
304 Theorem unletSound : forall t (e : term nil t), 304 Theorem unletSound : forall t (e : term nil t),
305 termDenote (unlet e HNil) HNil = termDenote e HNil. 305 termDenote (unlet e HNil) HNil = termDenote e HNil.
306 intros; apply unletSound'. 306 intros; apply unletSound'.
307 Qed. 307 Qed.
311 (** The [Let] removal optimization is a good case study of a simple transformation that may turn out to be much more work than expected, based on representation choices. In the second part of this chapter, we consider an alternate choice that produces a more pleasant experience. *) 311 (** The [Let] removal optimization is a good case study of a simple transformation that may turn out to be much more work than expected, based on representation choices. In the second part of this chapter, we consider an alternate choice that produces a more pleasant experience. *)
312 312
313 313
314 (** * Parametric Higher-Order Abstract Syntax *) 314 (** * Parametric Higher-Order Abstract Syntax *)
315 315
316 (** In contrast to first-order encodings,%\index{higher-order syntax}% _higher-order_ encodings avoid explicit modeling of variable identity. Instead, the binding constructs of an%\index{object language}% _object language_ (the language being formalized) can be represented using the binding constructs of the%\index{meta language}% _meta language_ (the language in which the formalization is done). The best known higher-order encoding is called%\index{higher-order abstract syntax}\index{HOAS}% _higher-order abstract syntax_ (HOAS) %\cite{HOAS}%, and we can start by attempting to apply it directly in Coq. *) 316 (** In contrast to first-order encodings,%\index{higher-order syntax}% _higher-order_ encodings avoid explicit modeling of variable identity. Instead, the binding constructs of an%\index{object language}% _object language_ (the language being formalized) can be represented using the binding constructs of the%\index{meta language}% _meta language_ (the language in which the formalization is done). The best known higher-order encoding is called%\index{higher-order abstract syntax}% _higher-order abstract syntax_ (HOAS) %\cite{HOAS}%, and we can start by attempting to apply it directly in Coq. *)
317 317
318 Module HigherOrder. 318 Module HigherOrder.
319 319
320 (** With HOAS, each object language binding construct is represented with a _function_ of the meta language. Here is what we get if we apply that idea within an inductive definition of term syntax. *) 320 (** With HOAS, each object language binding construct is represented with a _function_ of the meta language. Here is what we get if we apply that idea within an inductive definition of term syntax. *)
321 321
330 | Let : forall t1 t2, term t1 -> (term t1 -> term t2) -> term t2. 330 | Let : forall t1 t2, term t1 -> (term t1 -> term t2) -> term t2.
331 ]] 331 ]]
332 332
333 However, Coq rejects this definition for failing to meet the %\index{strict positivity requirement}%strict positivity restriction. For instance, the constructor [Abs] takes an argument that is a function over the same type family [term] that we are defining. Inductive definitions of this kind can be used to write non-terminating Gallina programs, which breaks the consistency of Coq's logic. 333 However, Coq rejects this definition for failing to meet the %\index{strict positivity requirement}%strict positivity restriction. For instance, the constructor [Abs] takes an argument that is a function over the same type family [term] that we are defining. Inductive definitions of this kind can be used to write non-terminating Gallina programs, which breaks the consistency of Coq's logic.
334 334
335 An alternate higher-order encoding is%\index{parametric higher-order abstract syntax}\index{PHOAS}% _parametric HOAS_, as introduced by Washburn and Weirich%~\cite{BGB}% for Haskell and tweaked by me%~\cite{PhoasICFP08}% for use in Coq. Here the idea is to parameterize the syntax type by a type family standing for a _representation of variables_. *) 335 An alternate higher-order encoding is%\index{parametric higher-order abstract syntax}\index{PHOAS|see{parametric higher-order abstract syntax}}% _parametric HOAS_, as introduced by Washburn and Weirich%~\cite{BGB}% for Haskell and tweaked by me%~\cite{PhoasICFP08}% for use in Coq. Here the idea is to parameterize the syntax type by a type family standing for a _representation of variables_. *)
336 336
337 Section var. 337 Section var.
338 Variable var : type -> Type. 338 Variable var : type -> Type.
339 339
340 Inductive term : type -> Type := 340 Inductive term : type -> Type :=
365 Abs (fun x => Abs (fun y => Plus (Var x) (Var y))). 365 Abs (fun x => Abs (fun y => Plus (Var x) (Var y))).
366 366
367 Example three_the_hard_way : Term Nat := fun var => 367 Example three_the_hard_way : Term Nat := fun var =>
368 App (App (add var) (Const 1)) (Const 2). 368 App (App (add var) (Const 1)) (Const 2).
369 369
370 (** The argument [var] does not even appear in the function body for [add]. How can that be? By giving our terms expressive types, we allow Coq to infer many arguments for us. In fact, we do not even need to name the [var] argument! Even though these formal parameters appear as underscores, they _are_ mentioned in the function bodies that type inference calculates. *) 370 (** The argument [var] does not even appear in the function body for [add]. How can that be? By giving our terms expressive types, we allow Coq to infer many arguments for us. In fact, we do not even need to name the [var] argument! *)
371 371
372 Example add' : Term (Func Nat (Func Nat Nat)) := fun _ => 372 Example add' : Term (Func Nat (Func Nat Nat)) := fun _ =>
373 Abs (fun x => Abs (fun y => Plus (Var x) (Var y))). 373 Abs (fun x => Abs (fun y => Plus (Var x) (Var y))).
374 374
375 Example three_the_hard_way' : Term Nat := fun _ => 375 Example three_the_hard_way' : Term Nat := fun _ =>
376 App (App (add' _) (Const 1)) (Const 2). 376 App (App (add' _) (Const 1)) (Const 2).
377
378 (** Even though the [var] formal parameters appear as underscores, they _are_ mentioned in the function bodies that type inference calculates. *)
377 379
378 380
379 (** ** Functional Programming with PHOAS *) 381 (** ** Functional Programming with PHOAS *)
380 382
381 (** It may not be at all obvious that the PHOAS representation admits the crucial computable operations. The key to effective deconstruction of PHOAS terms is one principle: treat the [var] parameter as an unconstrained choice of _which data should be annotated on each variable_. We will begin with a simple example, that of counting how many variable nodes appear in a PHOAS term. This operation requires no data annotated on variables, so we simply annotate variables with [unit] values. Note that, when we go under binders in the cases for [Abs] and [Let], we must provide the data value to annotate on the new variable we pass beneath. For our current choice of [unit] data, we always pass [tt]. *) 383 (** It may not be at all obvious that the PHOAS representation admits the crucial computable operations. The key to effective deconstruction of PHOAS terms is one principle: treat the [var] parameter as an unconstrained choice of _which data should be annotated on each variable_. We will begin with a simple example, that of counting how many variable nodes appear in a PHOAS term. This operation requires no data annotated on variables, so we simply annotate variables with [unit] values. Note that, when we go under binders in the cases for [Abs] and [Let], we must provide the data value to annotate on the new variable we pass beneath. For our current choice of [unit] data, we always pass [tt]. *)