Skip to content

Commit 6b27740

Browse files
Zdancewicnchappe
authored andcommitted
most of a port of ITrees mrec to CTrees
1 parent 2a7b3b8 commit 6b27740

File tree

2 files changed

+569
-0
lines changed

2 files changed

+569
-0
lines changed

theories/Interp/Recursion.v

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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

Comments
 (0)