-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEffect.agda
65 lines (49 loc) · 1.9 KB
/
Effect.agda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
-- Core of an extensbile-effects library
-- Implementation based on:
-- "Modular Semantics for Algebraic Effects"
-- https://studenttheses.uu.nl/handle/20.500.12932/37758
-- (I use their 'Sig' construction, to stay in Set₀)
-- (I also use their 'fold' function, to implement generic handlers)
-- "Freer Monads, More Extensible Effects"
-- https://okmij.org/ftp/Haskell/extensible/more.pdf
-- (I use their list-indexed Eff type, to help Agda's unifier)
module Freer.Effect where
open import Function.Base
open import Data.List
open import Data.Fin using (fromℕ<)
open import Data.Nat using (_<_)
-- Type of effect signatures
record Sig : Set₁ where
constructor _▹_
field Cmd : Set
field Res : Cmd → Set
open Sig
-- Non-dependent Sig constructor
_▸_ : Set → Set → Sig
C ▸ R = C ▹ λ _ → R
-- "Algebras over an effect signature"
-- (i.e. 'type of call-like commands')
_-alg_ : Sig → Set → Set
E -alg A = (c : Cmd E) → (Res E c → A) → A
-- Free monad over an effect (aka _⋆_)
data Eff (Ss : List Sig) (A : Set) : Set where
pure : A → Eff Ss A
call : ∀ {n} → lookup Ss n -alg (Eff Ss A)
-- General-purpose traversal function over Eff Ss
fold : ∀{A B Ss} → (A → B) → (∀{n} → (lookup Ss n) -alg B) → Eff Ss A → B
fold a→b call' (pure a) = a→b a
fold a→b call' (call c k) = call' c (fold a→b call' ∘ k)
-- Inverse of 'pure'
escape : ∀{A} → Eff [] A → A
escape (pure a) = a
-- A single call and nothing else.
-- (For use in do-blocks)
invoke : ∀{Ss} n → {{p : n < length Ss}}
→ (c : Cmd (lookup Ss (fromℕ< p)))
→ Eff Ss (Res (lookup Ss (fromℕ< p)) c)
invoke n {{pf}} c = call {n = fromℕ< pf} c pure
-- Eff S is a RawMonad
open import Effect.Monad
rawMonad : ∀{Ss} → RawMonad (Eff Ss)
rawMonad = mkRawMonad _ pure λ ea a→eb → fold a→eb call ea
open module M {Ss} = RawMonad (rawMonad {Ss}) public hiding (pure)