G7: Mieszane typy induktywno-koinduktywne [TODO]
From Typonomikon Require Import BC2f.
From Typonomikon Require Import F2.
Cthulhu zawsze płynie w lewo (TODO)
Pierwsze podejście (TODO)
Module Cthulhu_v1.
Inductive CthulhuCI (C I A : Type) : Type :=
| E
| N : A -> C -> I -> CthulhuCI C I A.
Arguments E {C I A}.
Arguments N {C I A} _ _ _.
Module CI.
CoInductive CthulhuC (I A : Type) : Type := MkC
{
Out : CthulhuCI (CthulhuC I A) I A;
}.
Arguments Out {I A} _.
Inductive Cthulhu (A : Type) : Type :=
| In : CthulhuC (Cthulhu A) A -> Cthulhu A.
Arguments In {A} _.
Definition out {A : Type} (c : Cthulhu A) : CthulhuC (Cthulhu A) A :=
match c with
| In c' => c'
end.
CoFixpoint replicateI (n : nat) : CthulhuC (Cthulhu nat) nat :=
{|
Out := N n (replicateI (S n)) (In {| Out := E; |});
|}.
Definition replicate (n : nat) : Cthulhu nat :=
In (replicateI n).
End CI.
Module IC.
Inductive CthulhuI (C A : Type) : Type :=
| In : CthulhuCI C (CthulhuI C A) A -> CthulhuI C A.
Arguments In {C A} _.
CoInductive Cthulhu (A : Type) : Type := MkC
{
Out : CthulhuI (Cthulhu A) A;
}.
Arguments MkC {A} _.
Arguments Out {A} _.
CoFixpoint replicate (n : nat) : Cthulhu nat :=
{|
Out := In (N n (replicate (S n)) (In E));
|}.
End IC.
End Cthulhu_v1.
Module Cthulhu_v2.
Inductive CthulhuIC (I C : Type -> Type) (A : Type) : Type :=
| E
| N : A -> C A -> I A -> CthulhuIC I C A.
Arguments E {I C A}.
Arguments N {I C A} _ _ _.
Inductive CthulhuI (C : Type -> Type) (A : Type) : Type :=
| In : CthulhuIC (CthulhuI C) C A -> CthulhuI C A.
Arguments In {C A} _.
CoInductive Cthulhu (A : Type) : Type := MkC
{
Out : CthulhuI Cthulhu A;
}.
Arguments MkC {A} _.
Arguments Out {A} _.
Fixpoint mapI
{C : Type -> Type} (map : forall {A B : Type}, (A -> B) -> C A -> C B)
{A B : Type} (f : A -> B)
(c : CthulhuI C A) : CthulhuI C B :=
match c with
| In E => In E
| In (N v l r) => In (N (f v) (map f l) (mapI (@map) f r))
end.
Fail
CoFixpoint map {A B : Type} (f : A -> B) (c : Cthulhu A) : Cthulhu B :=
{|
Out :=
match Out c with
| In E => In E
| In (N v l r) => In (N (f v) (map f l) (mapI (@map) f r))
end;
|}.
Fail
Definition map {A B : Type} (f : A -> B) (c : Cthulhu A) : Cthulhu B :=
cofix map (c : Cthulhu A) : Cthulhu B :=
match Out c with
| In E => MkC (In E)
| In (N v l r) => MkC (In
(fix mapI (ci : CthulhuI Cthulhu A) : CthulhuI Cthulhu B :=
match ci with
| In E => In E
| In (N v l r) => In (N (f v) (map l) (mapI r))
end) r)
end.
End Cthulhu_v2.
Module Cthulhu_v3.
Inductive TreeF (A X : Type) : Type :=
| E : TreeF A X
| N : A -> TreeF A X -> X -> TreeF A X.
Arguments E {A X}.
Arguments N {A X} _ _ _.
CoInductive Tree (A : Type) : Type :=
{
Out : TreeF A (Tree A);
}.
Arguments Out {A} _.
Fixpoint inums (n : nat) : TreeF nat (Tree nat) :=
match n with
| 0 => E
| S n' => N n' (inums n') {| Out := E |}
end.
CoFixpoint nums (n : nat) : Tree nat :=
{|
Out := N n (inums n) (nums (S n));
|}.
Fixpoint leftmostF {A X : Type} (t : TreeF A X) : option A :=
match t with
| E => None
| N v l _ =>
match leftmostF l with
| None => Some v
| Some x => Some x
end
end.
Definition leftmost {A : Type} (t : Tree A) : option A :=
match Out t with
| E => None
| N v l _ =>
match leftmostF l with
| None => Some v
| Some x => Some x
end
end.
Definition leftmost' {A : Type} (t : Tree A) : option A :=
leftmostF (Out t).
Lemma leftmost_leftmost' :
forall {A : Type} (t : Tree A),
leftmost t = leftmost' t.
Proof.
destruct t as [[]]; cbn; reflexivity.
Qed.
Fixpoint mapF {A B X Y : Type} (f : A -> B) (g : X -> Y) (t : TreeF A X) {struct t} : TreeF B Y :=
match t with
| E => E
| N x l r => N (f x) (mapF f g l) (g r)
end.
Fixpoint complete {A : Type} (n : nat) (x : A) (t : Tree A) : TreeF A (Tree A) :=
match n with
| 0 => E
| S n' => N x (complete n' x t) t
end.
Fail CoFixpoint complete' {A : Type} (n : nat) (x : A) : Tree A :=
{|
Out :=
N x
((fix aux (n : nat) : TreeF A (Tree A) :=
match n with
| 0 => E
| S n' => N x (aux n') (complete' n x)
end) n)
(complete' n x);
|}.
Fail Definition max (n : nat) (m : conat) : conat := max (from_nat n) m.
Basic observers
End Cthulhu_v3.
Wycinanki-indukcjanki, czyli jak wyciąć typ mieszany z typu koinduktywnego (TODO)
Module InductiveScissors.
CoInductive NETree (A : Type) : Type :=
{
root : A;
left : option (NETree A);
right : option (NETree A);
}.
Arguments root {A} _.
Arguments left {A} _.
Arguments right {A} _.
Inductive WFL {A : Type} : NETree A -> Prop :=
| WFL_None : forall {t : NETree A}, left t = None -> WFL t
| WFL_Some : forall {t t' : NETree A}, left t = Some t' -> WFL t' ->
WFL t.
Arguments WFL_None {A t} _.
CoInductive WF {A : Type} (t : NETree A) : Prop :=
{
rootWF : WFL t;
rightWF : right t = None \/ exists t' : NETree A, right t = Some t' /\ WF t'
}.
End InductiveScissors.
Transformatory strumieni (TODO)
Pierwsze podejście
Module StreamProcessor_v1.
Inductive SPXY (X Y A B : Type) : Type :=
| PutX : B -> X -> SPXY X Y A B
| GetX : (A -> Y) -> SPXY X Y A B.
Arguments PutX {X Y A B} _ _.
Arguments GetX {X Y A B} _.
CoInductive SP' (A B : Type) : Type :=
{
Out : SPXY (SP' A B) (SP' A B) A B;
}.
Arguments Out {A B} _.
Inductive WF {A B : Type} : SP' A B -> Type :=
| WF_Put :
forall (sp : SP' A B) (h : B) (t : SP' A B),
Out sp = PutX h t -> WF sp
| wF_Get :
forall (sp : SP' A B) (get : A -> SP' A B),
Out sp = GetX get -> (forall a : A, WF (get a)) -> WF sp.
Record SP (A B : Type) : Type :=
{
sp : SP' A B;
wf : WF sp;
}.
Definition compSP {A B C : Type} (f : SP A B) (g : SP B C) : SP A C.
Proof.
esplit. Unshelve. all: cycle 1.
- destruct f as [f wff], g as [g wfg].
revert f g wff wfg. cofix compSP. intros.
inversion wfg as [g' h t H1 H2 | g' get H1 H2 H3].
+ refine {| Out := PutX h _ |}.
Abort.
The first, naive way of doing it.
End StreamProcessor_v1.
Module StreamProcessor_v2.
Set Primitive Projections.
Inductive SPX (X A B : Type) : Type :=
| PutX : B -> X -> SPX X A B
| GetX : (A -> SPX X A B) -> SPX X A B.
Arguments PutX {X A B} _ _.
Arguments GetX {X A B} _.
CoInductive SP (A B : Type) : Type := MkSP
{
Out : SPX (SP A B) A B;
}.
Arguments MkSP {A B} _.
Arguments Out {A B} _.
Notation SP' A B := (SPX (SP A B) A B).
Notation Put := (fun b x => MkSP (PutX b x)).
Notation Get := (fun f => MkSP (GetX f)).
Fail CoFixpoint toStream {A B : Type} (sp : SP A B) (s : Stream A) : Stream B :=
match Out sp with
| PutX b sp' => Cons b (toStream sp' s)
| GetX sp' => toStream (MkSP (sp' (hd s))) (tl s)
end.
Fail Fixpoint SPX_to_Stream {X A B : Type} (sp : SPX X A B) (s : Stream A) : Stream B :=
match sp with
| PutX b sp' => Cons b (SPX_to_Stream sp')
| GetX sp' => SPX_to_Stream (sp' (hd s)) (tl s)
end.
The first, naive way of doing it.
Fixpoint head {X A B : Type} (sp : SPX X A B) (s : Stream A) : B :=
match sp with
| PutX h _ => h
| GetX sp' => head (sp' (hd s)) (tl s)
end.
Fixpoint tail {X A B : Type} (sp : SPX X A B) (s : Stream A) : X * Stream A :=
match sp with
| PutX _ t => (t, s)
| GetX sp' => tail (sp' (hd s)) (tl s)
end.
CoFixpoint toStream {A B : Type} (sp : SP A B) (s : Stream A) : Stream B :=
match Out sp with
| PutX h t => Cons h (toStream t s)
| GetX sp' =>
let (sp'', s') := tail (sp' (hd s)) (tl s) in
Cons (head (sp' (hd s)) (tl s)) (toStream sp'' s')
end.
CoFixpoint toStream1 {A B : Type} (sp : SP A B) (s : Stream A) : Stream B :=
Cons (head (Out sp) s) (let '(sp', s') := tail (Out sp) s in toStream1 sp' s').
A better way.
Fixpoint aux {X A B : Type} (sp : SPX X A B) (s : Stream A) : B * (X * Stream A) :=
match sp with
| PutX h t => (h, (t, s))
| GetX sp' => aux (sp' (hd s)) (tl s)
end.
CoFixpoint toStream' {A B : Type} (sp : SP A B) (s : Stream A) : Stream B :=
let '(b, (sp', s')) := aux (Out sp) s in
Cons b (toStream' sp' s').
Lighter syntax.
CoFixpoint toStream'' {A B : Type} (f : SP A B) (s : Stream A) : Stream B :=
match Out f with
| PutX h t => scons h (toStream'' t s)
| GetX g =>
let '(h, (f', s')) := aux (g (hd s)) (tl s) in
scons h (toStream'' f' s')
end.
Some proofs.
Lemma head_aux :
forall {X A B : Type} (sp : SPX X A B) (s : Stream A),
head sp s = fst (aux sp s).
Proof.
fix IH 4.
intros X A B [h t | g'] s; cbn; [easy |].
now apply IH.
Qed.
Lemma tail_aux :
forall {X A B : Type} (sp : SPX X A B) (s : Stream A),
tail sp s = snd (aux sp s).
Proof.
fix IH 4.
intros X A B [h t | g'] s; cbn; [easy |].
now apply IH.
Qed.
Lemma hd_toStream :
forall {A B : Type} (sp : SP A B) (s : Stream A),
hd (toStream sp s) = head (Out sp) s.
Proof.
intros A B sp; cbn.
destruct (Out sp) as [h t | sp'] eqn: Heq; cbn; intros; [easy |].
now destruct (tail (sp' (hd s)) (tl s)) eqn: Heq'; cbn.
Qed.
Lemma hd_toStream' :
forall {A B : Type} (sp : SP A B) (s : Stream A),
hd (toStream' sp s) = head (Out sp) s.
Proof.
intros A B sp; cbn.
induction (Out sp) as [h sp' | sp']; cbn; intros; [easy |].
now rewrite H.
Qed.
Lemma tl_toStream :
forall {A B : Type} (sp : SP A B) (s : Stream A),
tl (toStream sp s) =
let '(sp', s') := tail (Out sp) s in toStream sp' s'.
Proof.
intros A B sp; cbn.
destruct (Out sp) as [h sp' | sp']; cbn; intros; [easy |].
now destruct (tail (sp' (hd s)) (tl s)); cbn.
Qed.
Lemma tl_toStream' :
forall {A B : Type} (sp : SP A B) (s : Stream A),
tl (toStream' sp s) =
let '(sp', s') := tail (Out sp) s in toStream' sp' s'.
Proof.
intros A B sp; cbn.
induction (Out sp) as [h sp' | sp']; cbn; intros; [easy |].
now rewrite H.
Qed.
Lemma toStream_toStream' :
forall {A B : Type} (sp : SP A B) (s : Stream A),
sim (toStream sp s) (toStream' sp s).
Proof.
cofix CH.
constructor.
- now rewrite hd_toStream, hd_toStream'.
- rewrite tl_toStream, tl_toStream'.
destruct (tail (Out sp) s).
now apply CH.
Qed.
Lemma toStream_toStream1 :
forall {A B : Type} (sp : SP A B) (s : Stream A),
sim (toStream sp s) (toStream1 sp s).
Proof.
cofix CH.
constructor.
- now rewrite hd_toStream; cbn.
- rewrite tl_toStream; cbn.
destruct (tail (Out sp) s).
now apply CH.
Qed.
Composition of stream processors.
CoFixpoint compSP {A B C : Type} (sp1 : SP A B) (sp2 : SP B C) : SP A C.
Proof.
constructor.
destruct (Out sp2) as [c sp2' | sp2'] eqn: Hsp2; intros.
- apply (PutX c).
apply (compSP _ _ _ sp1 sp2').
- induction (Out sp1) as [b sp1' | sp1'] eqn: Hsp1.
+ admit.
+ apply GetX; intros a.
Abort.
CoFixpoint compSP {A B C : Type} (sp1 : SP A B) (sp2 : SP B C) : SP A C.
Proof.
refine (
(fix aux (sp2 : SPX (SP B C) B C) : SP A C :=
match sp2 with
| PutX c sp2' => _
| GetX sp2' => _
end
)
(Out sp2)
).
- constructor.
apply (PutX c).
admit.
- destruct (Out sp1) as [b sp1' | sp1'].
+ apply aux. apply sp2'. exact b.
+ constructor.
apply GetX; intros a.
Abort.
Definition compSP {A B C : Type} (sp1 : SP A B) (sp2 : SP B C) : SP A C.
Proof.
destruct sp1 as [sp1], sp2 as [sp2].
constructor.
induction sp2 as [c sp2' | sp2' IH].
- admit.
- apply GetX; intros a.
apply IH.
Abort.
End StreamProcessor_v2.
Definiowanie dziwnych funkcji (TODO)
Podejście pierwsze
Module ZipWith_v1.
Unset Guard Checking.
CoFixpoint fib : Stream nat := scons 0 (zipWith plus fib (scons 1 fib)).
Set Guard Checking.
Inductive TXY (X Y A : Type) : Type :=
| ConsXY : A -> X -> TXY X Y A
| ZipWithXY : (A -> A -> A) -> Y -> Y -> TXY X Y A.
Arguments ConsXY {X Y A} _ _.
Arguments ZipWithXY {X Y A} _ _ _.
Inductive SX (X A : Type) : Type :=
| SConsX : A -> X -> SX X A
| SZipWithX : (A -> A -> A) -> SX X A -> SX X A -> SX X A.
Arguments SConsX {X A} _ _.
Arguments SZipWithX {X A} _ _ _.
CoInductive StreamZipWith (A : Type) : Type :=
{
Out : TXY (StreamZipWith A) (SX (StreamZipWith A) A) A;
}.
Arguments Out {A} _.
Definition ZipWith (A : Type) : Type := SX (StreamZipWith A) A.
Definition StreamZipWith_to_ZipWith {A : Type} (s : StreamZipWith A) : ZipWith A :=
match Out s with
| ConsXY h t => SConsX h t
| ZipWithXY f l r => SZipWithX f l r
end.
Definition Cons {A : Type} (h : A) (t : StreamZipWith A) : StreamZipWith A :=
{|
Out := ConsXY h t;
|}.
Definition ZipWith' {A : Type} (f : A -> A -> A) (l r : StreamZipWith A) : StreamZipWith A :=
{|
Out := ZipWithXY f (StreamZipWith_to_ZipWith l) (StreamZipWith_to_ZipWith r);
|}.
Fixpoint whnf {A : Type} (z : ZipWith A) : A * StreamZipWith A :=
match z with
| SConsX h t => (h, t)
| SZipWithX f l r =>
let '(h1, t1) := whnf l in
let '(h2, t2) := whnf r in
(f h1 h2, ZipWith' f t1 t2)
end.
CoFixpoint toStream {A : Type} (z : StreamZipWith A) : Stream A :=
match Out z with
| ConsXY h t => scons h (toStream t)
| ZipWithXY f l r =>
let (h1, t1) := whnf l in
let (h2, t2) := whnf r in
scons (f h1 h2) (toStream (ZipWith' f t1 t2))
end.
CoFixpoint fibSZW : StreamZipWith nat.
Proof.
apply (Cons 0).
refine {| Out := ZipWithXY plus _ _ |}.
exact (StreamZipWith_to_ZipWith fibSZW).
exact (SConsX 1 fibSZW).
Abort.
End ZipWith_v1.
Module ZipWith_v2.
Unset Guard Checking.
Set Guard Checking.
Inductive CI : Type := Ind | Coind.
Inductive Base (C A : Type) : CI -> Type :=
| BCons : forall {ci : CI}, A -> C -> Base C A ci
| BZipWith : forall {ci : CI}, (A -> A -> A) -> Base C A Ind -> Base C A Ind -> Base C A ci
| BInj : C -> Base C A Ind.
Arguments BCons {C A ci} _ _.
Arguments BZipWith {C A ci} _ _ _.
Arguments BInj {C A} _.
CoInductive ZipWith (A : Type) : Type :=
{
Out : Base (ZipWith A) A Coind;
}.
Arguments Out {A} _.
Definition Cons {A : Type} (h : A) (t : ZipWith A) : ZipWith A :=
{|
Out := BCons h t;
|}.
Definition ZipWith' {A : Type} (f : A -> A -> A) (l r : ZipWith A) : ZipWith A :=
{|
Out := BZipWith f (BInj l) (BInj r);
|}.
CoFixpoint fib' : ZipWith nat.
Proof.
apply (Cons 0).
refine (ZipWith' plus _ _).
exact fib'.
apply (Cons 1). exact fib'.
Defined.
End ZipWith_v2.