Mercurial > cpdt > repo
comparison src/GeneralRec.v @ 354:dc99dffdf20a
Co-inductive non-termination monads
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Wed, 26 Oct 2011 18:37:47 -0400 |
parents | 3322367e955d |
children | 62fdf0993e05 |
comparison
equal
deleted
inserted
replaced
353:3322367e955d | 354:dc99dffdf20a |
---|---|
275 ]] | 275 ]] |
276 | 276 |
277 Some more recent Coq features provide more convenient syntax for defining recursive functions. Interested readers can consult the Coq manual about the commands %\index{Function}%[Function] and %\index{Program Fixpoint}%[Program Fixpoint]. *) | 277 Some more recent Coq features provide more convenient syntax for defining recursive functions. Interested readers can consult the Coq manual about the commands %\index{Function}%[Function] and %\index{Program Fixpoint}%[Program Fixpoint]. *) |
278 | 278 |
279 | 279 |
280 (** * A Non-Termination Monad *) | 280 (** * A Non-Termination Monad Inspired by Domain Theory *) |
281 | 281 |
282 Section computation. | 282 Section computation. |
283 Variable A : Type. | 283 Variable A : Type. |
284 | 284 |
285 Definition computation := | 285 Definition computation := |
575 Defined. | 575 Defined. |
576 | 576 |
577 Lemma test_looper : run (looper true) tt. | 577 Lemma test_looper : run (looper true) tt. |
578 exists 1; reflexivity. | 578 exists 1; reflexivity. |
579 Qed. | 579 Qed. |
580 | |
581 | |
582 (** * Co-Inductive Non-Termination Monads *) | |
583 | |
584 CoInductive thunk (A : Type) : Type := | |
585 | Answer : A -> thunk A | |
586 | Think : thunk A -> thunk A. | |
587 | |
588 CoFixpoint TBind (A B : Type) (m1 : thunk A) (m2 : A -> thunk B) : thunk B := | |
589 match m1 with | |
590 | Answer x => m2 x | |
591 | Think m1' => Think (TBind m1' m2) | |
592 end. | |
593 | |
594 CoInductive thunk_eq A : thunk A -> thunk A -> Prop := | |
595 | EqAnswer : forall x, thunk_eq (Answer x) (Answer x) | |
596 | EqThinkL : forall m1 m2, thunk_eq m1 m2 -> thunk_eq (Think m1) m2 | |
597 | EqThinkR : forall m1 m2, thunk_eq m1 m2 -> thunk_eq m1 (Think m2). | |
598 | |
599 Section thunk_eq_coind. | |
600 Variable A : Type. | |
601 Variable P : thunk A -> thunk A -> Prop. | |
602 | |
603 Hypothesis H : forall m1 m2, P m1 m2 | |
604 -> match m1, m2 with | |
605 | Answer x1, Answer x2 => x1 = x2 | |
606 | Think m1', Think m2' => P m1' m2' | |
607 | Think m1', _ => P m1' m2 | |
608 | _, Think m2' => P m1 m2' | |
609 end. | |
610 | |
611 Theorem thunk_eq_coind : forall m1 m2, P m1 m2 -> thunk_eq m1 m2. | |
612 cofix; intros; | |
613 match goal with | |
614 | [ H' : P _ _ |- _ ] => specialize (H H'); clear H' | |
615 end; destruct m1; destruct m2; subst; repeat constructor; auto. | |
616 Qed. | |
617 End thunk_eq_coind. | |
618 | |
619 Definition frob A (m : thunk A) : thunk A := | |
620 match m with | |
621 | Answer x => Answer x | |
622 | Think m' => Think m' | |
623 end. | |
624 | |
625 Theorem frob_eq : forall A (m : thunk A), frob m = m. | |
626 destruct m; reflexivity. | |
627 Qed. | |
628 | |
629 Theorem thunk_eq_frob : forall A (m1 m2 : thunk A), | |
630 thunk_eq (frob m1) (frob m2) | |
631 -> thunk_eq m1 m2. | |
632 intros; repeat rewrite frob_eq in *; auto. | |
633 Qed. | |
634 | |
635 Ltac findDestr := match goal with | |
636 | [ |- context[match ?E with Answer _ => _ | Think _ => _ end] ] => | |
637 match E with | |
638 | context[match _ with Answer _ => _ | Think _ => _ end] => fail 1 | |
639 | _ => destruct E | |
640 end | |
641 end. | |
642 | |
643 Theorem thunk_eq_refl : forall A (m : thunk A), thunk_eq m m. | |
644 intros; apply (thunk_eq_coind (fun m1 m2 => m1 = m2)); crush; findDestr; reflexivity. | |
645 Qed. | |
646 | |
647 Hint Resolve thunk_eq_refl. | |
648 | |
649 Theorem tleft_identity : forall A B (a : A) (f : A -> thunk B), | |
650 thunk_eq (TBind (Answer a) f) (f a). | |
651 intros; apply thunk_eq_frob; crush. | |
652 Qed. | |
653 | |
654 Theorem tright_identity : forall A (m : thunk A), | |
655 thunk_eq (TBind m (@Answer _)) m. | |
656 intros; apply (thunk_eq_coind (fun m1 m2 => m1 = TBind m2 (@Answer _))); crush; | |
657 findDestr; reflexivity. | |
658 Qed. | |
659 | |
660 Lemma TBind_Answer : forall (A B : Type) (v : A) (m2 : A -> thunk B), | |
661 TBind (Answer v) m2 = m2 v. | |
662 intros; rewrite <- (frob_eq (TBind (Answer v) m2)); | |
663 simpl; findDestr; reflexivity. | |
664 Qed. | |
665 | |
666 Hint Rewrite TBind_Answer : cpdt. | |
667 | |
668 Theorem tassociativity : forall A B C (m : thunk A) (f : A -> thunk B) (g : B -> thunk C), | |
669 thunk_eq (TBind (TBind m f) g) (TBind m (fun x => TBind (f x) g)). | |
670 intros; apply (thunk_eq_coind (fun m1 m2 => (exists m, | |
671 m1 = TBind (TBind m f) g | |
672 /\ m2 = TBind m (fun x => TBind (f x) g)) | |
673 \/ m1 = m2)); crush; eauto; repeat (findDestr; crush; eauto). | |
674 Qed. | |
675 | |
676 CoFixpoint fact (n acc : nat) : thunk nat := | |
677 match n with | |
678 | O => Answer acc | |
679 | S n' => Think (fact n' (S n' * acc)) | |
680 end. | |
681 | |
682 Inductive eval A : thunk A -> A -> Prop := | |
683 | EvalAnswer : forall x, eval (Answer x) x | |
684 | EvalThink : forall m x, eval m x -> eval (Think m) x. | |
685 | |
686 Hint Rewrite frob_eq : cpdt. | |
687 | |
688 Lemma eval_frob : forall A (c : thunk A) x, | |
689 eval (frob c) x | |
690 -> eval c x. | |
691 crush. | |
692 Qed. | |
693 | |
694 Theorem eval_fact : eval (fact 5 1) 120. | |
695 repeat (apply eval_frob; simpl; constructor). | |
696 Qed. | |
697 | |
698 (** [[ | |
699 CoFixpoint fib (n : nat) : thunk nat := | |
700 match n with | |
701 | 0 => Answer 1 | |
702 | 1 => Answer 1 | |
703 | _ => TBind (fib (pred n)) (fun n1 => | |
704 TBind (fib (pred (pred n))) (fun n2 => | |
705 Answer (n1 + n2))) | |
706 end. | |
707 ]] | |
708 *) | |
709 | |
710 | |
711 CoInductive comp (A : Type) : Type := | |
712 | Ret : A -> comp A | |
713 | Bnd : forall B, comp B -> (B -> comp A) -> comp A. | |
714 | |
715 Inductive exec A : comp A -> A -> Prop := | |
716 | ExecRet : forall x, exec (Ret x) x | |
717 | ExecBnd : forall B (c : comp B) (f : B -> comp A) x1 x2, exec (A := B) c x1 | |
718 -> exec (f x1) x2 | |
719 -> exec (Bnd c f) x2. | |
720 | |
721 Hint Constructors exec. | |
722 | |
723 Definition comp_eq A (c1 c2 : comp A) := forall r, exec c1 r <-> exec c2 r. | |
724 | |
725 Ltac inverter := repeat match goal with | |
726 | [ H : exec _ _ |- _ ] => inversion H; []; crush | |
727 end. | |
728 | |
729 Theorem cleft_identity : forall A B (a : A) (f : A -> comp B), | |
730 comp_eq (Bnd (Ret a) f) (f a). | |
731 red; crush; inverter; eauto. | |
732 Qed. | |
733 | |
734 Theorem cright_identity : forall A (m : comp A), | |
735 comp_eq (Bnd m (@Ret _)) m. | |
736 red; crush; inverter; eauto. | |
737 Qed. | |
738 | |
739 Lemma cassociativity1 : forall A B C (f : A -> comp B) (g : B -> comp C) r c, | |
740 exec c r | |
741 -> forall m, c = Bnd (Bnd m f) g | |
742 -> exec (Bnd m (fun x => Bnd (f x) g)) r. | |
743 induction 1; crush. | |
744 match goal with | |
745 | [ H : Bnd _ _ = Bnd _ _ |- _ ] => injection H; clear H; intros; try subst | |
746 end. | |
747 move H3 after A. | |
748 generalize dependent B0. | |
749 do 2 intro. | |
750 subst. | |
751 crush. | |
752 inversion H; clear H; crush. | |
753 eauto. | |
754 Qed. | |
755 | |
756 Lemma cassociativity2 : forall A B C (f : A -> comp B) (g : B -> comp C) r c, | |
757 exec c r | |
758 -> forall m, c = Bnd m (fun x => Bnd (f x) g) | |
759 -> exec (Bnd (Bnd m f) g) r. | |
760 induction 1; crush. | |
761 match goal with | |
762 | [ H : Bnd _ _ = Bnd _ _ |- _ ] => injection H; clear H; intros; try subst | |
763 end. | |
764 move H3 after B. | |
765 generalize dependent B0. | |
766 do 2 intro. | |
767 subst. | |
768 crush. | |
769 inversion H0; clear H0; crush. | |
770 eauto. | |
771 Qed. | |
772 | |
773 Hint Resolve cassociativity1 cassociativity2. | |
774 | |
775 Theorem cassociativity : forall A B C (m : comp A) (f : A -> comp B) (g : B -> comp C), | |
776 comp_eq (Bnd (Bnd m f) g) (Bnd m (fun x => Bnd (f x) g)). | |
777 red; crush; eauto. | |
778 Qed. | |
779 | |
780 CoFixpoint mergeSort'' A (le : A -> A -> bool) (ls : list A) : comp (list A) := | |
781 if le_lt_dec 2 (length ls) | |
782 then let lss := partition ls in | |
783 Bnd (mergeSort'' le (fst lss)) (fun ls1 => | |
784 Bnd (mergeSort'' le (snd lss)) (fun ls2 => | |
785 Ret (merge le ls1 ls2))) | |
786 else Ret ls. | |
787 | |
788 Definition frob' A (c : comp A) := | |
789 match c with | |
790 | Ret x => Ret x | |
791 | Bnd _ c' f => Bnd c' f | |
792 end. | |
793 | |
794 Lemma frob'_eq : forall A (c : comp A), frob' c = c. | |
795 destruct c; reflexivity. | |
796 Qed. | |
797 | |
798 Hint Rewrite frob'_eq : cpdt. | |
799 | |
800 Lemma exec_frob : forall A (c : comp A) x, | |
801 exec (frob' c) x | |
802 -> exec c x. | |
803 crush. | |
804 Qed. | |
805 | |
806 Lemma test_mergeSort'' : exec (mergeSort'' leb (1 :: 2 :: 36 :: 8 :: 19 :: nil)) | |
807 (1 :: 2 :: 8 :: 19 :: 36 :: nil). | |
808 repeat (apply exec_frob; simpl; econstructor). | |
809 Qed. | |
810 | |
811 Definition curriedAdd (n : nat) := Ret (fun m : nat => Ret (n + m)). | |
812 | |
813 (** [[ | |
814 Definition testCurriedAdd := | |
815 Bnd (curriedAdd 2) (fun f => f 3). | |
816 ]] | |
817 | |
818 << | |
819 Error: Universe inconsistency. | |
820 >> | |
821 *) | |
822 | |
823 | |
824 (** * Comparing the Options *) | |
825 | |
826 Definition curriedAdd' (n : nat) := Return (fun m : nat => Return (n + m)). | |
827 | |
828 Definition testCurriedAdd := | |
829 Bind (curriedAdd' 2) (fun f => f 3). | |
830 | |
831 Fixpoint map A B (f : A -> computation B) (ls : list A) : computation (list B) := | |
832 match ls with | |
833 | nil => Return nil | |
834 | x :: ls' => Bind (f x) (fun x' => | |
835 Bind (map f ls') (fun ls'' => | |
836 Return (x' :: ls''))) | |
837 end. | |
838 | |
839 Theorem test_map : run (map (fun x => Return (S x)) (1 :: 2 :: 3 :: nil)) (2 :: 3 :: 4 :: nil). | |
840 exists 1; reflexivity. | |
841 Qed. |