comparison src/StackMachine.v @ 447:9e3333bd08a1

Proofreading pass through Chapter 2
author Adam Chlipala <adam@chlipala.net>
date Fri, 17 Aug 2012 12:22:26 -0400
parents 89c67796754e
children 2740b8a23cce
comparison
equal deleted inserted replaced
446:a0c604da96d3 447:9e3333bd08a1
8 *) 8 *)
9 9
10 10
11 (** %\chapter{Some Quick Examples}% *) 11 (** %\chapter{Some Quick Examples}% *)
12 12
13 (** I will start off by jumping right in to a fully worked set of examples, building certified compilers from increasingly complicated source languages to stack machines. We will meet a few useful tactics and see how they can be used in manual proofs, and we will also see how easily these proofs can be automated instead. This chapter is not meant to give full explanations of the features that are employed. Rather, it is meant more as an advertisement of what is possible. Later chapters will introduce all of the concepts in bottom-up fashion. 13 (** I will start off by jumping right in to a fully worked set of examples, building certified compilers from increasingly complicated source languages to stack machines. We will meet a few useful tactics and see how they can be used in manual proofs, and we will also see how easily these proofs can be automated instead. This chapter is not meant to give full explanations of the features that are employed. Rather, it is meant more as an advertisement of what is possible. Later chapters will introduce all of the concepts in bottom-up fashion. In other words, it is expected that most readers will not understand what exactly is going on here, but I hope this demo will whet your appetite for the remaining chapters!
14 14
15 As always, you can step through the source file <<StackMachine.v>> for this chapter interactively in Proof General. Alternatively, to get a feel for the whole lifecycle of creating a Coq development, you can enter the pieces of source code in this chapter in a new <<.v>> file in an Emacs buffer. If you do the latter, include these two lines at the start of the file. *) 15 As always, you can step through the source file <<StackMachine.v>> for this chapter interactively in Proof General. Alternatively, to get a feel for the whole lifecycle of creating a Coq development, you can enter the pieces of source code in this chapter in a new <<.v>> file in an Emacs buffer. If you do the latter, include these two lines at the start of the file. *)
16 16
17 Require Import Bool Arith List CpdtTactics. 17 Require Import Bool Arith List CpdtTactics.
18 Set Implicit Arguments. 18 Set Implicit Arguments.
28 28
29 (** We begin with the syntax of the source language.%\index{Vernacular commands!Inductive}% *) 29 (** We begin with the syntax of the source language.%\index{Vernacular commands!Inductive}% *)
30 30
31 Inductive binop : Set := Plus | Times. 31 Inductive binop : Set := Plus | Times.
32 32
33 (** Our first line of Coq code should be unsurprising to ML and Haskell programmers. We define an %\index{algebraic datatypes}%algebraic datatype [binop] to stand for the binary operators of our source language. There are just two wrinkles compared to ML and Haskell. First, we use the keyword [Inductive], in place of <<data>>, <<datatype>>, or <<type>>. This is not just a trivial surface syntax difference; inductive types in Coq are much more expressive than garden variety algebraic datatypes, essentially enabling us to encode all of mathematics, though we begin humbly in this chapter. Second, there is the %\index{Gallina terms!Set}%[: Set] fragment, which declares that we are defining a datatype that should be thought of as a constituent of programs. Later, we will see other options for defining datatypes in the universe of proofs or in an infinite hierarchy of universes, encompassing both programs and proofs, that bis useful in higher-order constructions. *) 33 (** Our first line of Coq code should be unsurprising to ML and Haskell programmers. We define an %\index{algebraic datatypes}%algebraic datatype [binop] to stand for the binary operators of our source language. There are just two wrinkles compared to ML and Haskell. First, we use the keyword [Inductive], in place of <<data>>, <<datatype>>, or <<type>>. This is not just a trivial surface syntax difference; inductive types in Coq are much more expressive than garden variety algebraic datatypes, essentially enabling us to encode all of mathematics, though we begin humbly in this chapter. Second, there is the %\index{Gallina terms!Set}%[: Set] fragment, which declares that we are defining a datatype that should be thought of as a constituent of programs. Later, we will see other options for defining datatypes in the universe of proofs or in an infinite hierarchy of universes, encompassing both programs and proofs, that is useful in higher-order constructions. *)
34 34
35 Inductive exp : Set := 35 Inductive exp : Set :=
36 | Const : nat -> exp 36 | Const : nat -> exp
37 | Binop : binop -> exp -> exp -> exp. 37 | Binop : binop -> exp -> exp -> exp.
38 38
178 178
179 Eval simpl in progDenote (compile (Binop Times (Binop Plus (Const 2) (Const 2)) 179 Eval simpl in progDenote (compile (Binop Times (Binop Plus (Const 2) (Const 2))
180 (Const 7))) nil. 180 (Const 7))) nil.
181 (** [= Some (28 :: nil) : option stack] *) 181 (** [= Some (28 :: nil) : option stack] *)
182 182
183 (** %\smallskip{}%So far so good, but how can we be sure the compiler operates correctly for _all_ input programs? *)
183 184
184 (** ** Translation Correctness *) 185 (** ** Translation Correctness *)
185 186
186 (** We are ready to prove that our compiler is implemented correctly. We can use a new vernacular command [Theorem] to start a correctness proof, in terms of the semantics we defined earlier:%\index{Vernacular commands!Theorem}% *) 187 (** We are ready to prove that our compiler is implemented correctly. We can use a new vernacular command [Theorem] to start a correctness proof, in terms of the semantics we defined earlier:%\index{Vernacular commands!Theorem}% *)
187 188
522 523
523 reflexivity. 524 reflexivity.
524 Qed. 525 Qed.
525 (* end thide *) 526 (* end thide *)
526 527
527 (** This proof can be shortened and made automated, but we leave that as an exercise for the reader. *) 528 (** This proof can be shortened and made automated, but we leave that task as an exercise for the reader. *)
528 529
529 530
530 (** * Typed Expressions *) 531 (** * Typed Expressions *)
531 532
532 (** In this section, we will build on the initial example by adding additional expression forms that depend on static typing of terms for safety. *) 533 (** In this section, we will build on the initial example by adding additional expression forms that depend on static typing of terms for safety. *)
563 Inductive texp : type -> Set := 564 Inductive texp : type -> Set :=
564 | TNConst : nat -> texp Nat 565 | TNConst : nat -> texp Nat
565 | TBConst : bool -> texp Bool 566 | TBConst : bool -> texp Bool
566 | TBinop : forall t1 t2 t, tbinop t1 t2 t -> texp t1 -> texp t2 -> texp t. 567 | TBinop : forall t1 t2 t, tbinop t1 t2 t -> texp t1 -> texp t2 -> texp t.
567 568
568 (** Thanks to our use of dependent types, every well-typed [texp] represents a well-typed source expression, by construction. This turns out to be very convenient for many things we might want to do with expressions. For instance, it is easy to adapt our interpreter approach to defining semantics. We start by defining a function mapping the types of our languages into Coq types: *) 569 (** Thanks to our use of dependent types, every well-typed [texp] represents a well-typed source expression, by construction. This turns out to be very convenient for many things we might want to do with expressions. For instance, it is easy to adapt our interpreter approach to defining semantics. We start by defining a function mapping the types of our object language into Coq types: *)
569 570
570 Definition typeDenote (t : type) : Set := 571 Definition typeDenote (t : type) : Set :=
571 match t with 572 match t with
572 | Nat => nat 573 | Nat => nat
573 | Bool => bool 574 | Bool => bool
682 | TiBConst _ b => (b, s) 683 | TiBConst _ b => (b, s)
683 | TiBinop _ _ _ _ b => 684 | TiBinop _ _ _ _ b =>
684 let '(arg1, (arg2, s')) := s in 685 let '(arg1, (arg2, s')) := s in
685 ((tbinopDenote b) arg1 arg2, s') 686 ((tbinopDenote b) arg1 arg2, s')
686 end. 687 end.
687 688 ]]
688 ]] 689
689 690 The Coq type checker complains that:
690 The Coq type-checker complains that:
691 691
692 << 692 <<
693 The term "(n, s)" has type "(nat * vstack ts)%type" 693 The term "(n, s)" has type "(nat * vstack ts)%type"
694 while it is expected to have type "vstack ?119". 694 while it is expected to have type "vstack ?119".
695 >> 695 >>
702 Fixpoint tprogDenote ts ts' (p : tprog ts ts') : vstack ts -> vstack ts' := 702 Fixpoint tprogDenote ts ts' (p : tprog ts ts') : vstack ts -> vstack ts' :=
703 match p with 703 match p with
704 | TNil _ => fun s => s 704 | TNil _ => fun s => s
705 | TCons _ _ _ i p' => fun s => tprogDenote p' (tinstrDenote i s) 705 | TCons _ _ _ i p' => fun s => tprogDenote p' (tinstrDenote i s)
706 end. 706 end.
707
708 (** The same argument-postponing trick is crucial for this definition. *)
707 709
708 710
709 (** ** Translation *) 711 (** ** Translation *)
710 712
711 (** To define our compilation, it is useful to have an auxiliary function for concatenating two stack machine programs. *) 713 (** To define our compilation, it is useful to have an auxiliary function for concatenating two stack machine programs. *)