|
| 1 | +From ExtLib Require Import |
| 2 | + Structures.Functor |
| 3 | + Structures.Monad. |
| 4 | + |
| 5 | +From ITree Require Import |
| 6 | + Basics.Basics |
| 7 | + Indexed.Sum. |
| 8 | + |
| 9 | +Import ITree.Basics.Basics.Monads. |
| 10 | + |
| 11 | +From CTree Require Import |
| 12 | + CTree |
| 13 | + Eq |
| 14 | + Eq.Epsilon |
| 15 | + Eq.IterFacts |
| 16 | + Eq.SSimAlt |
| 17 | + Misc.Pure |
| 18 | + Fold. |
| 19 | + |
| 20 | +Import CTreeNotations. |
| 21 | +Open Scope ctree_scope. |
| 22 | + |
| 23 | +(** * General recursion *) |
| 24 | + |
| 25 | +(** *** Mutual recursion *) |
| 26 | + |
| 27 | +(* Implementation of the fixpoint combinator over interaction |
| 28 | + * trees. |
| 29 | + * |
| 30 | + * The implementation is based on the discussion here |
| 31 | + * https://gmalecha.github.io/reflections/2018/compositional-coinductive-recursion-in-coq |
| 32 | + *) |
| 33 | + |
| 34 | +(* The indexed type [D : Type -> Type] gives the signature of |
| 35 | + a set of functions. For example, a pair of mutually recursive |
| 36 | + [even : nat -> bool] and [odd : nat -> bool] can be declared |
| 37 | + as follows: |
| 38 | +
|
| 39 | +[[ |
| 40 | + Inductive D : Type -> Type := |
| 41 | + | Even : nat -> D bool |
| 42 | + | Odd : nat -> D bool. |
| 43 | +]] |
| 44 | +
|
| 45 | + Their mutually recursive definition can then be written finitely |
| 46 | + (without [Fixpoint]): |
| 47 | +
|
| 48 | +[[ |
| 49 | + Definition def : D ~> itree (D +' void1) := fun _ d => |
| 50 | + match d with |
| 51 | + | Even n => match n with |
| 52 | + | O => ret true |
| 53 | + | S m => trigger (Odd m) |
| 54 | + end |
| 55 | + | Odd n => match n with |
| 56 | + | O => ret false |
| 57 | + | S m => trigger (Even m) |
| 58 | + end |
| 59 | + end. |
| 60 | +]] |
| 61 | +
|
| 62 | + The function [interp_mrec] below then ties the knot. |
| 63 | +
|
| 64 | +[[ |
| 65 | + Definition f : D ~> itree void1 := |
| 66 | + interp_mrec def. |
| 67 | +
|
| 68 | + Definition even (n : nat) : itree void1 bool := f _ (Even n). |
| 69 | + Definition odd (n : nat) : itree void1 bool := f _ (Odd n). |
| 70 | +]] |
| 71 | +
|
| 72 | + The result is still in the [itree] monad of possibly divergent |
| 73 | + computations, because [mutfix_itree] doesn't care whether |
| 74 | + the mutually recursive definition is well-founded. |
| 75 | +
|
| 76 | + *) |
| 77 | + |
| 78 | +(** Interpret an itree in the context of a mutually recursive |
| 79 | + definition ([ctx]). *) |
| 80 | +Definition interp_mrec {D E B : Type -> Type} |
| 81 | + (ctx : D ~> ctree (D +' E) B) : ctree (D +' E) B ~> ctree E B := |
| 82 | + fun R => |
| 83 | + CTree.iter (fun t : ctree (D +' E) B R => |
| 84 | + match observe t with |
| 85 | + | RetF r => Ret (inr r) |
| 86 | + | StuckF => Stuck |
| 87 | + | StepF t => Step (Ret (inl t)) |
| 88 | + | GuardF t => Ret (inl t) |
| 89 | + | VisF (inl1 d) k => Ret (inl (ctx _ d >>= k)) |
| 90 | + | VisF (inr1 e) k => Vis e (fun x => Ret (inl (k x))) |
| 91 | + | BrF c k => Br c (fun x => Ret (inl (k x))) |
| 92 | + end). |
| 93 | + |
| 94 | +Arguments interp_mrec {D E B} ctx [T]. |
| 95 | + |
| 96 | +(** Unfold a mutually recursive definition into separate trees, |
| 97 | + resolving the mutual references. *) |
| 98 | +Definition mrec {D E B : Type -> Type} |
| 99 | + (ctx : D ~> ctree (D +' E) B) : D ~> ctree E B := |
| 100 | + fun R d => interp_mrec ctx (ctx _ d). |
| 101 | + |
| 102 | +Arguments mrec {D E B} ctx [T]. |
| 103 | + |
| 104 | +(** Make a recursive call in the handler argument of [mrec]. *) |
| 105 | +Definition trigger_inl1 {D E B : Type -> Type} : D ~> ctree (D +' E) B |
| 106 | + := fun _ d => CTree.trigger (inl1 d). |
| 107 | + |
| 108 | +Arguments trigger_inl1 {D E B} [T]. |
| 109 | + |
| 110 | +(** Here's some syntactic sugar with a notation [mrec-fix]. *) |
| 111 | + |
| 112 | +(** Short for endofunctions, used in [mrec_fix] and [rec_fix]. *) |
| 113 | +(* Local Notation endo T := (T -> T). *) |
| 114 | + |
| 115 | +(* Definition mrec_fix {D E : Type -> Type} *) |
| 116 | +(* (ctx : endo (D ~> itree (D +' E))) *) |
| 117 | +(* : D ~> itree E *) |
| 118 | +(* := mrec (ctx trigger_inl1). *) |
| 119 | + |
| 120 | +(* Notation "'mrec-fix' f d := g" := *) |
| 121 | +(* (let D := _ in *) |
| 122 | +(* mrec_fix (D := D) (fun (f : forall T, D T -> _) T (d : D T) => g)) *) |
| 123 | +(* (at level 200, f ident, d pattern). *) |
| 124 | +(* (* No idea what a good level would be. *) *) |
| 125 | + |
| 126 | +(** *** Simple recursion *) |
| 127 | + |
| 128 | +Inductive callE (A B : Type) : Type -> Type := |
| 129 | +| Call : A -> callE A B B. |
| 130 | + |
| 131 | +Arguments Call {A B}. |
| 132 | + |
| 133 | +(** Get the [A] contained in a [callE A B]. *) |
| 134 | +Definition unCall {A B T} (e : callE A B T) : A := |
| 135 | + match e with |
| 136 | + | Call a => a |
| 137 | + end. |
| 138 | + |
| 139 | +(** Lift a function on [A] to a morphism on [callE]. *) |
| 140 | +Definition calling {A B} {F : Type -> Type} |
| 141 | + (f : A -> F B) : callE A B ~> F := |
| 142 | + fun _ e => |
| 143 | + match e with |
| 144 | + | Call a => f a |
| 145 | + end. |
| 146 | + |
| 147 | +(* TODO: This is identical to [callWith] but [rec] finds a universe |
| 148 | + inconsistency with [calling], and not with [calling']. |
| 149 | + The inconsistency now pops up later (currently in [Events.Env]) *) |
| 150 | +Definition calling' {X Y} {F B : Type -> Type} |
| 151 | + (f : X -> ctree F B Y) : callE X Y ~> ctree F B := |
| 152 | + fun _ e => |
| 153 | + match e with |
| 154 | + | Call a => f a |
| 155 | + end. |
| 156 | + |
| 157 | +(* Interpret a single recursive definition. *) |
| 158 | +Definition rec {E B : Type -> Type} {X Y : Type} |
| 159 | + (body : X -> ctree (callE X Y +' E) B Y) : |
| 160 | + X -> ctree E B Y := |
| 161 | + fun a => mrec (calling' body) (Call a). |
| 162 | + |
| 163 | +(** An easy way to construct an event suitable for use with [rec]. |
| 164 | + [call] is an event representing the recursive call. Since in general, the |
| 165 | + function might have other events of type [E], the resulting itree has |
| 166 | + type [(callE A B +' E)]. |
| 167 | +*) |
| 168 | +Definition call {E B X Y} (x:X) : ctree (callE X Y +' E) B Y := |
| 169 | + CTree.trigger (inl1 (Call x)). |
| 170 | + |
| 171 | +(* (** Here's some syntactic sugar with a notation [mrec-fix]. *) *) |
| 172 | + |
| 173 | +(* Definition rec_fix {E : Type -> Type} {A B : Type} *) |
| 174 | +(* (body : endo (A -> itree (callE A B +' E) B)) *) |
| 175 | +(* : A -> itree E B *) |
| 176 | +(* := rec (body call). *) |
| 177 | + |
| 178 | +(* Notation "'rec-fix' f a := g" := (rec_fix (fun f a => g)) *) |
| 179 | +(* (at level 200, f ident, a pattern). *) |
| 180 | +(* No idea what a good level would be. *) |
0 commit comments