|
1 | 1 | import Effects.Container |
2 | 2 | import Effects.Prog |
| 3 | +import Effects.IOEff |
3 | 4 |
|
4 | 5 | open scoped Container |
5 | 6 |
|
@@ -67,16 +68,110 @@ def run |
67 | 68 | def eval (s : S) (p : Prog (State S :: effs) α) : Prog effs α := |
68 | 69 | Prod.snd <$> run s p |
69 | 70 |
|
| 71 | +def runViaIO' |
| 72 | + [IOEff ∈ effs] |
| 73 | + (p : Prog (State S :: effs) α) : |
| 74 | + IO.Ref S → Prog effs (S × α) := |
| 75 | + Prog.foldP |
| 76 | + (P := fun _ => IO.Ref S → Prog effs (S × α)) |
| 77 | + (var0 := fun x => fun iost => |
| 78 | + IOEff.embed iost.get |>.bind (fun st => pure (st, x))) |
| 79 | + (varS := id) |
| 80 | + (op := fun ⟨c, k⟩ => |
| 81 | + match c with |
| 82 | + | .inl StateOps.getOp => fun iost => |
| 83 | + IOEff.embed iost.get |>.bind (fun st => k st iost) |
| 84 | + | .inl (StateOps.putOp s') => fun iost => |
| 85 | + IOEff.embed (iost.set s') |>.bind (fun _ => k () iost) |
| 86 | + | .inr s => fun iost => |
| 87 | + Prog.op ⟨s, fun p => k p iost⟩) |
| 88 | + (scp := fun ⟨c, k⟩ => |
| 89 | + match c with |
| 90 | + | .inl x => nomatch x |
| 91 | + | .inr s => fun iost => Prog.scp ⟨s, fun p => ProgN.varS (k p iost)⟩) |
| 92 | + p |
| 93 | + |
| 94 | +def runViaIO |
| 95 | + [IOEff ∈ effs] |
| 96 | + (s : IO.Ref S) |
| 97 | + (p : Prog (State S :: effs) α) |
| 98 | + : Prog effs (S × α) := |
| 99 | + runViaIO' p s |
| 100 | + |
| 101 | +def evalViaIO |
| 102 | + [IOEff ∈ effs] |
| 103 | + (s : IO.Ref S) |
| 104 | + (p : Prog (State S :: effs) α) |
| 105 | + : Prog effs α := |
| 106 | + Prod.snd <$> runViaIO' p s |
| 107 | + |
70 | 108 | end State |
71 | 109 |
|
72 | 110 | section Examples |
73 | 111 |
|
74 | 112 | open State |
75 | 113 |
|
76 | | -def tick {effs} [State Nat ∈ effs] : Prog effs Unit := do |
77 | | - let i ← get |
78 | | - put (1 + i) |
79 | | - |
80 | | -#guard Prog.run (State.run 0 (do tick; tick)) = (2, ()) |
| 114 | +def ticks |
| 115 | + {effs} |
| 116 | + [State Nat ∈ effs] |
| 117 | + : Prog effs Nat := do |
| 118 | + let n ← get |
| 119 | + put (n + 1) |
| 120 | + let m ← get |
| 121 | + pure (n + 2 * m) |
| 122 | + |
| 123 | + |
| 124 | +def runTicksPure : Nat × Nat := |
| 125 | + ticks |
| 126 | + |> State.run 0 |
| 127 | + |> Prog.run |
| 128 | + |
| 129 | +#guard runTicksPure = (1, 2) |
| 130 | + |
| 131 | +def runTicksIO : IO (Nat × Nat) := do |
| 132 | + let ref ← IO.mkRef 0 |
| 133 | + ticks |
| 134 | + |> State.runViaIO ref |
| 135 | + |> IOEff.run |
| 136 | + |
| 137 | +/-- |
| 138 | +info: (1, 2) |
| 139 | +-/ |
| 140 | +#guard_msgs in |
| 141 | +#eval runTicksIO |
| 142 | + |
| 143 | +def twoState |
| 144 | + {effs} |
| 145 | + [State Bool ∈ effs] |
| 146 | + [State Nat ∈ effs] |
| 147 | + : Prog effs Unit := do |
| 148 | + let b ← get |
| 149 | + let n ← get |
| 150 | + put (n + 1) |
| 151 | + let n ← get |
| 152 | + put (b && n > 5) |
| 153 | + |
| 154 | +def runTwoStatePure : Nat × Bool × Unit := |
| 155 | + twoState |
| 156 | + |> State.run true |
| 157 | + |> State.run 4 |
| 158 | + |> Prog.run |
| 159 | + |
| 160 | +#guard runTwoStatePure = (5, false, ()) |
| 161 | + |
| 162 | +def runTwoStateIO : IO (Nat × Nat × Bool × Unit) := do |
| 163 | + let ref : IO.Ref Nat ← IO.mkRef 4 |
| 164 | + let res ← twoState |
| 165 | + |> State.run true |
| 166 | + |> State.runViaIO ref |
| 167 | + |> IOEff.run |
| 168 | + -- Also check that the IO.Ref was updated |
| 169 | + (← ref.get, res) |> pure |
| 170 | + |
| 171 | +/-- |
| 172 | +info: (5, 5, false, ()) |
| 173 | +-/ |
| 174 | +#guard_msgs in |
| 175 | +#eval runTwoStateIO |
81 | 176 |
|
82 | 177 | end Examples |
0 commit comments