comparison src/StackMachine.v @ 207:a7be5d9a2fd4

Converted StackMachine
author Adam Chlipala <adamc@hcoop.net>
date Fri, 06 Nov 2009 17:10:27 -0500
parents 3f4576f15130
children b149a07b9b5b
comparison
equal deleted inserted replaced
206:3f4576f15130 207:a7be5d9a2fd4
585 | true, true => true 585 | true, true => true
586 | false, false => true 586 | false, false => true
587 | _, _ => false 587 | _, _ => false
588 end. 588 end.
589 589
590 Fixpoint eq_nat (n1 n2 : nat) {struct n1} : bool := 590 Fixpoint eq_nat (n1 n2 : nat) : bool :=
591 match n1, n2 with 591 match n1, n2 with
592 | O, O => true 592 | O, O => true
593 | S n1', S n2' => eq_nat n1' n2' 593 | S n1', S n2' => eq_nat n1' n2'
594 | _, _ => false 594 | _, _ => false
595 end. 595 end.
596 596
597 Fixpoint lt (n1 n2 : nat) {struct n1} : bool := 597 Fixpoint lt (n1 n2 : nat) : bool :=
598 match n1, n2 with 598 match n1, n2 with
599 | O, S _ => true 599 | O, S _ => true
600 | S n1', S n2' => lt n1' n2' 600 | S n1', S n2' => lt n1' n2'
601 | _, _ => false 601 | _, _ => false
602 end. 602 end.
603 603
604 (** Now we can interpret binary operators: *) 604 (** Now we can interpret binary operators: *)
605 605
606 Definition tbinopDenote arg1 arg2 res (b : tbinop arg1 arg2 res) 606 Definition tbinopDenote arg1 arg2 res (b : tbinop arg1 arg2 res)
607 : typeDenote arg1 -> typeDenote arg2 -> typeDenote res := 607 : typeDenote arg1 -> typeDenote arg2 -> typeDenote res :=
608 match b in (tbinop arg1 arg2 res) return (typeDenote arg1 -> typeDenote arg2 -> typeDenote res) with 608 match b in (tbinop arg1 arg2 res)
609 return (typeDenote arg1 -> typeDenote arg2 -> typeDenote res) with
609 | TPlus => plus 610 | TPlus => plus
610 | TTimes => mult 611 | TTimes => mult
611 | TEq Nat => eq_nat 612 | TEq Nat => eq_nat
612 | TEq Bool => eq_bool 613 | TEq Bool => eq_bool
613 | TLt => lt 614 | TLt => lt
614 end. 615 end.
615 616
616 (** This function has just a few differences from the denotation functions we saw earlier. First, [tbinop] is an indexed type, so its indices become additional arguments to [tbinopDenote]. Second, we need to perform a genuine %\textit{%#<i>#dependent pattern match#</i>#%}% to come up with a definition of this function that type-checks. In each branch of the [match], we need to use branch-specific information about the indices to [tbinop]. General type inference that takes such information into account is undecidable, and Coq avoids pursuing special heuristics for the problem, instead asking users to write annotations, like we see above on the line with [match]. 617 (** This function has just a few differences from the denotation functions we saw earlier. First, [tbinop] is an indexed type, so its indices become additional arguments to [tbinopDenote]. Second, we need to perform a genuine %\textit{%#<i>#dependent pattern match#</i>#%}% to come up with a definition of this function that type-checks. In each branch of the [match], we need to use branch-specific information about the indices to [tbinop]. General type inference that takes such information into account is undecidable, so it is often necessary to write annotations, like we see above on the line with [match].
617 618
618 The [in] annotation restates the type of the term being case-analyzed. Though we use the same names for the indices as we use in the type of the original argument binder, these are actually fresh variables, and they are %\textit{%#<i>#binding occurrences#</i>#%}%. Their scope is the [return] clause. That is, [arg1], [arg2], and [arg3] are new bound variables bound only within the return clause [typeDenote arg1 -> typeDenote arg2 -> typeDenote res]. By being explicit about the functional relationship between the type indices and the match result, we regain decidable type inference. 619 The [in] annotation restates the type of the term being case-analyzed. Though we use the same names for the indices as we use in the type of the original argument binder, these are actually fresh variables, and they are %\textit{%#<i>#binding occurrences#</i>#%}%. Their scope is the [return] clause. That is, [arg1], [arg2], and [arg3] are new bound variables bound only within the return clause [typeDenote arg1 -> typeDenote arg2 -> typeDenote res]. By being explicit about the functional relationship between the type indices and the match result, we regain decidable type inference.
619 620
621 In fact, recent Coq versions use some heuristics that can save us the trouble of writing [match] annotations, and those heuristics get the job done in this case. We can get away with writing just: *)
622
623 (* begin hide *)
624 Reset tbinopDenote.
625 (* end hide *)
626 Definition tbinopDenote arg1 arg2 res (b : tbinop arg1 arg2 res)
627 : typeDenote arg1 -> typeDenote arg2 -> typeDenote res :=
628 match b with
629 | TPlus => plus
630 | TTimes => mult
631 | TEq Nat => eq_nat
632 | TEq Bool => eq_bool
633 | TLt => lt
634 end.
635
636 (**
620 The same tricks suffice to define an expression denotation function in an unsurprising way: 637 The same tricks suffice to define an expression denotation function in an unsurprising way:
621 *) 638 *)
622 639
623 Fixpoint texpDenote t (e : texp t) {struct e} : typeDenote t := 640 Fixpoint texpDenote t (e : texp t) : typeDenote t :=
624 match e in (texp t) return (typeDenote t) with 641 match e with
625 | TNConst n => n 642 | TNConst n => n
626 | TBConst b => b 643 | TBConst b => b
627 | TBinop _ _ _ b e1 e2 => (tbinopDenote b) (texpDenote e1) (texpDenote e2) 644 | TBinop _ _ _ b e1 e2 => (tbinopDenote b) (texpDenote e1) (texpDenote e2)
628 end. 645 end.
629 646
630 (** We can evaluate a few example programs to convince ourselves that this semantics is correct. *) 647 (** We can evaluate a few example programs to convince ourselves that this semantics is correct. *)
631 648
632 Eval simpl in texpDenote (TNConst 42). 649 Eval simpl in texpDenote (TNConst 42).
633 (** [[ 650 (** [= 42 : typeDenote Nat] *)
634 = 42 : typeDenote Nat 651
635 ]] *)
636 Eval simpl in texpDenote (TBConst true). 652 Eval simpl in texpDenote (TBConst true).
637 (** [[ 653 (** [= true : typeDenote Bool] *)
638 = true : typeDenote Bool 654
639 ]] *)
640 Eval simpl in texpDenote (TBinop TTimes (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)). 655 Eval simpl in texpDenote (TBinop TTimes (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)).
641 (** [[ 656 (** [= 28 : typeDenote Nat] *)
642 = 28 : typeDenote Nat 657
643 ]] *)
644 Eval simpl in texpDenote (TBinop (TEq Nat) (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)). 658 Eval simpl in texpDenote (TBinop (TEq Nat) (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)).
645 (** [[ 659 (** [= false : typeDenote Bool] *)
646 = false : typeDenote Bool 660
647 ]] *)
648 Eval simpl in texpDenote (TBinop TLt (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)). 661 Eval simpl in texpDenote (TBinop TLt (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)).
649 (** [[ 662 (** [= true : typeDenote Bool] *)
650 = true : typeDenote Bool
651 ]] *)
652 663
653 664
654 (** ** Target Language *) 665 (** ** Target Language *)
655 666
656 (** Now we want to define a suitable stack machine target for compilation. In the example of the untyped language, stack machine programs could encounter stack underflows and "get stuck." This was unfortunate, since we had to deal with this complication even though we proved that our compiler never produced underflowing programs. We could have used dependent types to force all stack machine programs to be underflow-free. 667 (** Now we want to define a suitable stack machine target for compilation. In the example of the untyped language, stack machine programs could encounter stack underflows and "get stuck." This was unfortunate, since we had to deal with this complication even though we proved that our compiler never produced underflowing programs. We could have used dependent types to force all stack machine programs to be underflow-free.
689 | t :: ts' => typeDenote t * vstack ts' 700 | t :: ts' => typeDenote t * vstack ts'
690 end%type. 701 end%type.
691 702
692 (** This is another [Set]-valued function. This time it is recursive, which is perfectly valid, since [Set] is not treated specially in determining which functions may be written. We say that the value stack of an empty stack type is any value of type [unit], which has just a single value, [tt]. A nonempty stack type leads to a value stack that is a pair, whose first element has the proper type and whose second element follows the representation for the remainder of the stack type. 703 (** This is another [Set]-valued function. This time it is recursive, which is perfectly valid, since [Set] is not treated specially in determining which functions may be written. We say that the value stack of an empty stack type is any value of type [unit], which has just a single value, [tt]. A nonempty stack type leads to a value stack that is a pair, whose first element has the proper type and whose second element follows the representation for the remainder of the stack type.
693 704
694 This idea of programming with types can take a while to internalize, but it enables a very simple definition of instruction denotation. We have the same kind of type annotations for the dependent [match], but everything else is like what you might expect from a Lisp-like version of ML that ignored type information. Nonetheless, the fact that [tinstrDenote] passes the type-checker guarantees that our stack machine programs can never go wrong. *) 705 This idea of programming with types can take a while to internalize, but it enables a very simple definition of instruction denotation. Our definition is like what you might expect from a Lisp-like version of ML that ignored type information. Nonetheless, the fact that [tinstrDenote] passes the type-checker guarantees that our stack machine programs can never go wrong. *)
695 706
696 Definition tinstrDenote ts ts' (i : tinstr ts ts') : vstack ts -> vstack ts' := 707 Definition tinstrDenote ts ts' (i : tinstr ts ts') : vstack ts -> vstack ts' :=
697 match i in (tinstr ts ts') return (vstack ts -> vstack ts') with 708 match i with
698 | TINConst _ n => fun s => (n, s) 709 | TINConst _ n => fun s => (n, s)
699 | TIBConst _ b => fun s => (b, s) 710 | TIBConst _ b => fun s => (b, s)
700 | TIBinop _ _ _ _ b => fun s => 711 | TIBinop _ _ _ _ b => fun s =>
701 match s with 712 match s with
702 (arg1, (arg2, s')) => ((tbinopDenote b) arg1 arg2, s') 713 (arg1, (arg2, s')) => ((tbinopDenote b) arg1 arg2, s')
705 716
706 (** Why do we choose to use an anonymous function to bind the initial stack in every case of the [match]? Consider this well-intentioned but invalid alternative version: 717 (** Why do we choose to use an anonymous function to bind the initial stack in every case of the [match]? Consider this well-intentioned but invalid alternative version:
707 718
708 [[ 719 [[
709 Definition tinstrDenote ts ts' (i : tinstr ts ts') (s : vstack ts) : vstack ts' := 720 Definition tinstrDenote ts ts' (i : tinstr ts ts') (s : vstack ts) : vstack ts' :=
710 match i in (tinstr ts ts') return (vstack ts') with 721 match i with
711 | TINConst _ n => (n, s) 722 | TINConst _ n => (n, s)
712 | TIBConst _ b => (b, s) 723 | TIBConst _ b => (b, s)
713 | TIBinop _ _ _ _ b => 724 | TIBinop _ _ _ _ b =>
714 match s with 725 match s with
715 (arg1, (arg2, s')) => ((tbinopDenote b) arg1 arg2, s') 726 (arg1, (arg2, s')) => ((tbinopDenote b) arg1 arg2, s')
720 731
721 The Coq type-checker complains that: 732 The Coq type-checker complains that:
722 733
723 [[ 734 [[
724 The term "(n, s)" has type "(nat * vstack ts)%type" 735 The term "(n, s)" has type "(nat * vstack ts)%type"
725 while it is expected to have type "vstack (Nat :: t)" 736 while it is expected to have type "vstack ?119".
737
738 ]]
739
740 The text [?119] stands for a unification variable. We can try to help Coq figure out the value of this variable with an explicit annotation on our [match] expression.
741
742 [[
743 Definition tinstrDenote ts ts' (i : tinstr ts ts') (s : vstack ts) : vstack ts' :=
744 match i in tinstr ts ts' return vstack ts' with
745 | TINConst _ n => (n, s)
746 | TIBConst _ b => (b, s)
747 | TIBinop _ _ _ _ b =>
748 match s with
749 (arg1, (arg2, s')) => ((tbinopDenote b) arg1 arg2, s')
750 end
751 end.
752
753 ]]
754
755 Now the error message changes.
756
757 [[
758 The term "(n, s)" has type "(nat * vstack ts)%type"
759 while it is expected to have type "vstack (Nat :: t)".
760
726 ]] 761 ]]
727 762
728 Recall from our earlier discussion of [match] annotations that we write the annotations to express to the type-checker the relationship between the type indices of the case object and the result type of the [match]. Coq chooses to assign to the wildcard [_] after [TINConst] the name [t], and the type error is telling us that the type checker cannot prove that [t] is the same as [ts]. By moving [s] out of the [match], we lose the ability to express, with [in] and [return] clauses, the relationship between the shared index [ts] of [s] and [i]. 763 Recall from our earlier discussion of [match] annotations that we write the annotations to express to the type-checker the relationship between the type indices of the case object and the result type of the [match]. Coq chooses to assign to the wildcard [_] after [TINConst] the name [t], and the type error is telling us that the type checker cannot prove that [t] is the same as [ts]. By moving [s] out of the [match], we lose the ability to express, with [in] and [return] clauses, the relationship between the shared index [ts] of [s] and [i].
729 764
730 There %\textit{%#<i>#are#</i>#%}% reasonably general ways of getting around this problem without pushing binders inside [match]es. However, the alternatives are significantly more involved, and the technique we use here is almost certainly the best choice, whenever it applies. 765 There %\textit{%#<i>#are#</i>#%}% reasonably general ways of getting around this problem without pushing binders inside [match]es. However, the alternatives are significantly more involved, and the technique we use here is almost certainly the best choice, whenever it applies.
731 766
732 *) 767 *)
733 768
734 (** We finish the semantics with a straightforward definition of program denotation. *) 769 (** We finish the semantics with a straightforward definition of program denotation. *)
735 770
736 Fixpoint tprogDenote ts ts' (p : tprog ts ts') {struct p} : vstack ts -> vstack ts' := 771 Fixpoint tprogDenote ts ts' (p : tprog ts ts') : vstack ts -> vstack ts' :=
737 match p in (tprog ts ts') return (vstack ts -> vstack ts') with 772 match p with
738 | TNil _ => fun s => s 773 | TNil _ => fun s => s
739 | TCons _ _ _ i p' => fun s => tprogDenote p' (tinstrDenote i s) 774 | TCons _ _ _ i p' => fun s => tprogDenote p' (tinstrDenote i s)
740 end. 775 end.
741 776
742 777
743 (** ** Translation *) 778 (** ** Translation *)
744 779
745 (** To define our compilation, it is useful to have an auxiliary function for concatenating two stack machine programs. *) 780 (** To define our compilation, it is useful to have an auxiliary function for concatenating two stack machine programs. *)
746 781
747 Fixpoint tconcat ts ts' ts'' (p : tprog ts ts') {struct p} : tprog ts' ts'' -> tprog ts ts'' := 782 Fixpoint tconcat ts ts' ts'' (p : tprog ts ts') : tprog ts' ts'' -> tprog ts ts'' :=
748 match p in (tprog ts ts') return (tprog ts' ts'' -> tprog ts ts'') with 783 match p with
749 | TNil _ => fun p' => p' 784 | TNil _ => fun p' => p'
750 | TCons _ _ _ i p1 => fun p' => TCons i (tconcat p1 p') 785 | TCons _ _ _ i p1 => fun p' => TCons i (tconcat p1 p')
751 end. 786 end.
752 787
753 (** With that function in place, the compilation is defined very similarly to how it was before, modulo the use of dependent typing. *) 788 (** With that function in place, the compilation is defined very similarly to how it was before, modulo the use of dependent typing. *)
754 789
755 Fixpoint tcompile t (e : texp t) (ts : tstack) {struct e} : tprog ts (t :: ts) := 790 Fixpoint tcompile t (e : texp t) (ts : tstack) : tprog ts (t :: ts) :=
756 match e in (texp t) return (tprog ts (t :: ts)) with 791 match e with
757 | TNConst n => TCons (TINConst _ n) (TNil _) 792 | TNConst n => TCons (TINConst _ n) (TNil _)
758 | TBConst b => TCons (TIBConst _ b) (TNil _) 793 | TBConst b => TCons (TIBConst _ b) (TNil _)
759 | TBinop _ _ _ b e1 e2 => tconcat (tcompile e2 _) 794 | TBinop _ _ _ b e1 e2 => tconcat (tcompile e2 _)
760 (tconcat (tcompile e1 _) (TCons (TIBinop _ b) (TNil _))) 795 (tconcat (tcompile e1 _) (TCons (TIBinop _ b) (TNil _)))
761 end. 796 end.
763 (** One interesting feature of the definition is the underscores appearing to the right of [=>] arrows. Haskell and ML programmers are quite familiar with compilers that infer type parameters to polymorphic values. In Coq, it is possible to go even further and ask the system to infer arbitrary terms, by writing underscores in place of specific values. You may have noticed that we have been calling functions without specifying all of their arguments. For instance, the recursive calls here to [tcompile] omit the [t] argument. Coq's %\textit{%#<i>#implicit argument#</i>#%}% mechanism automatically inserts underscores for arguments that it will probably be able to infer. Inference of such values is far from complete, though; generally, it only works in cases similar to those encountered with polymorphic type instantiation in Haskell and ML. 798 (** One interesting feature of the definition is the underscores appearing to the right of [=>] arrows. Haskell and ML programmers are quite familiar with compilers that infer type parameters to polymorphic values. In Coq, it is possible to go even further and ask the system to infer arbitrary terms, by writing underscores in place of specific values. You may have noticed that we have been calling functions without specifying all of their arguments. For instance, the recursive calls here to [tcompile] omit the [t] argument. Coq's %\textit{%#<i>#implicit argument#</i>#%}% mechanism automatically inserts underscores for arguments that it will probably be able to infer. Inference of such values is far from complete, though; generally, it only works in cases similar to those encountered with polymorphic type instantiation in Haskell and ML.
764 799
765 The underscores here are being filled in with stack types. That is, the Coq type inferencer is, in a sense, inferring something about the flow of control in the translated programs. We can take a look at exactly which values are filled in: *) 800 The underscores here are being filled in with stack types. That is, the Coq type inferencer is, in a sense, inferring something about the flow of control in the translated programs. We can take a look at exactly which values are filled in: *)
766 801
767 Print tcompile. 802 Print tcompile.
768 803 (** [[
769 (** [[
770
771 tcompile = 804 tcompile =
772 fix tcompile (t : type) (e : texp t) (ts : tstack) {struct e} : 805 fix tcompile (t : type) (e : texp t) (ts : tstack) {struct e} :
773 tprog ts (t :: ts) := 806 tprog ts (t :: ts) :=
774 match e in (texp t0) return (tprog ts (t0 :: ts)) with 807 match e in (texp t0) return (tprog ts (t0 :: ts)) with
775 | TNConst n => TCons (TINConst ts n) (TNil (Nat :: ts)) 808 | TNConst n => TCons (TINConst ts n) (TNil (Nat :: ts))
784 817
785 818
786 (** We can check that the compiler generates programs that behave appropriately on our sample programs from above: *) 819 (** We can check that the compiler generates programs that behave appropriately on our sample programs from above: *)
787 820
788 Eval simpl in tprogDenote (tcompile (TNConst 42) nil) tt. 821 Eval simpl in tprogDenote (tcompile (TNConst 42) nil) tt.
789 (** [[ 822 (** [= (42, tt) : vstack (Nat :: nil)] *)
790 = (42, tt) : vstack (Nat :: nil) 823
791 ]] *)
792 Eval simpl in tprogDenote (tcompile (TBConst true) nil) tt. 824 Eval simpl in tprogDenote (tcompile (TBConst true) nil) tt.
793 (** [[ 825 (** [= (true, tt) : vstack (Bool :: nil)] *)
794 = (true, tt) : vstack (Bool :: nil) 826
795 ]] *)
796 Eval simpl in tprogDenote (tcompile (TBinop TTimes (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt. 827 Eval simpl in tprogDenote (tcompile (TBinop TTimes (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt.
797 (** [[ 828 (** [= (28, tt) : vstack (Nat :: nil)] *)
798 = (28, tt) : vstack (Nat :: nil) 829
799 ]] *)
800 Eval simpl in tprogDenote (tcompile (TBinop (TEq Nat) (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt. 830 Eval simpl in tprogDenote (tcompile (TBinop (TEq Nat) (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt.
801 (** [[ 831 (** [= (false, tt) : vstack (Bool :: nil)] *)
802 = (false, tt) : vstack (Bool :: nil) 832
803 ]] *)
804 Eval simpl in tprogDenote (tcompile (TBinop TLt (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt. 833 Eval simpl in tprogDenote (tcompile (TBinop TLt (TBinop TPlus (TNConst 2) (TNConst 2)) (TNConst 7)) nil) tt.
805 (** [[ 834 (** [= (true, tt) : vstack (Bool :: nil)] *)
806 = (true, tt) : vstack (Bool :: nil)
807 ]] *)
808 835
809 836
810 (** ** Translation Correctness *) 837 (** ** Translation Correctness *)
811 838
812 (** We can state a correctness theorem similar to the last one. *) 839 (** We can state a correctness theorem similar to the last one. *)
813 840
814 Theorem tcompile_correct : forall t (e : texp t), tprogDenote (tcompile e nil) tt = (texpDenote e, tt). 841 Theorem tcompile_correct : forall t (e : texp t),
842 tprogDenote (tcompile e nil) tt = (texpDenote e, tt).
815 (* begin hide *) 843 (* begin hide *)
816 Abort. 844 Abort.
817 (* end hide *) 845 (* end hide *)
818 (* begin thide *) 846 (* begin thide *)
819 847
820 (** Again, we need to strengthen the theorem statement so that the induction will go through. This time, I will develop an alternative approach to this kind of proof, stating the key lemma as: *) 848 (** Again, we need to strengthen the theorem statement so that the induction will go through. This time, I will develop an alternative approach to this kind of proof, stating the key lemma as: *)
821 849
822 Lemma tcompile_correct' : forall t (e : texp t) 850 Lemma tcompile_correct' : forall t (e : texp t) ts (s : vstack ts),
823 ts (s : vstack ts), 851 tprogDenote (tcompile e ts) s = (texpDenote e, s).
824 tprogDenote (tcompile e ts) s
825 = (texpDenote e, s).
826 852
827 (** While lemma [compile_correct'] quantified over a program that is the "continuation" for the expression we are considering, here we avoid drawing in any extra syntactic elements. In addition to the source expression and its type, we also quantify over an initial stack type and a stack compatible with it. Running the compilation of the program starting from that stack, we should arrive at a stack that differs only in having the program's denotation pushed onto it. 853 (** While lemma [compile_correct'] quantified over a program that is the "continuation" for the expression we are considering, here we avoid drawing in any extra syntactic elements. In addition to the source expression and its type, we also quantify over an initial stack type and a stack compatible with it. Running the compilation of the program starting from that stack, we should arrive at a stack that differs only in having the program's denotation pushed onto it.
828 854
829 Let us try to prove this theorem in the same way that we settled on in the last section. *) 855 Let us try to prove this theorem in the same way that we settled on in the last section. *)
830 856
831 induction e; crush. 857 induction e; crush.
832 858
833 (** We are left with this unproved conclusion: 859 (** We are left with this unproved conclusion:
834 860
835 [[ 861 [[
836
837 tprogDenote 862 tprogDenote
838 (tconcat (tcompile e2 ts) 863 (tconcat (tcompile e2 ts)
839 (tconcat (tcompile e1 (arg2 :: ts)) 864 (tconcat (tcompile e1 (arg2 :: ts))
840 (TCons (TIBinop ts t) (TNil (res :: ts))))) s = 865 (TCons (TIBinop ts t) (TNil (res :: ts))))) s =
841 (tbinopDenote t (texpDenote e1) (texpDenote e2), s) 866 (tbinopDenote t (texpDenote e1) (texpDenote e2), s)
867
842 ]] 868 ]]
843 869
844 We need an analogue to the [app_ass] theorem that we used to rewrite the goal in the last section. We can abort this proof and prove such a lemma about [tconcat]. 870 We need an analogue to the [app_ass] theorem that we used to rewrite the goal in the last section. We can abort this proof and prove such a lemma about [tconcat].
845 *) 871 *)
872
846 Abort. 873 Abort.
847 874
848 Lemma tconcat_correct : forall ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'') 875 Lemma tconcat_correct : forall ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'')
849 (s : vstack ts), 876 (s : vstack ts),
850 tprogDenote (tconcat p p') s 877 tprogDenote (tconcat p p') s
858 885
859 Hint Rewrite tconcat_correct : cpdt. 886 Hint Rewrite tconcat_correct : cpdt.
860 887
861 (** We ask that the lemma be used for left-to-right rewriting, and we ask for the hint to be added to the hint database called [cpdt], which is the database used by [crush]. Now we are ready to return to [tcompile_correct'], proving it automatically this time. *) 888 (** We ask that the lemma be used for left-to-right rewriting, and we ask for the hint to be added to the hint database called [cpdt], which is the database used by [crush]. Now we are ready to return to [tcompile_correct'], proving it automatically this time. *)
862 889
863 Lemma tcompile_correct' : forall t (e : texp t) 890 Lemma tcompile_correct' : forall t (e : texp t) ts (s : vstack ts),
864 ts (s : vstack ts), 891 tprogDenote (tcompile e ts) s = (texpDenote e, s).
865 tprogDenote (tcompile e ts) s
866 = (texpDenote e, s).
867 induction e; crush. 892 induction e; crush.
868 Qed. 893 Qed.
869 894
870 (** We can register this main lemma as another hint, allowing us to prove the final theorem trivially. *) 895 (** We can register this main lemma as another hint, allowing us to prove the final theorem trivially. *)
871 896
872 Hint Rewrite tcompile_correct' : cpdt. 897 Hint Rewrite tcompile_correct' : cpdt.
873 898
874 Theorem tcompile_correct : forall t (e : texp t), tprogDenote (tcompile e nil) tt = (texpDenote e, tt). 899 Theorem tcompile_correct : forall t (e : texp t),
900 tprogDenote (tcompile e nil) tt = (texpDenote e, tt).
875 crush. 901 crush.
876 Qed. 902 Qed.
877 (* end thide *) 903 (* end thide *)