-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathInternal.hs
More file actions
115 lines (95 loc) · 3.6 KB
/
Copy pathInternal.hs
File metadata and controls
115 lines (95 loc) · 3.6 KB
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module Control.Monad.Eff.Internal where
import Data.OpenUnion
import Data.FTCQueue
-- |
-- Effectful arrow type: a function from a to b that also does effects
-- denoted by r
type Arr r a b = a -> Eff r b
-- |
-- An effectful function from 'a' to 'b' that is a composition
-- of several effectful functions. The paremeter r describes the overall
-- effect.
-- The composition members are accumulated in a type-aligned queue
type Arrs r a b = FTCQueue (Eff r) a b
-- |
-- The Eff monad (not a transformer!)
-- It is a fairly standard coroutine monad
-- It is NOT a Free monad! There are no Functor constraints
-- Status of a coroutine (client): done with the value of type w,
-- or sending a request of type Union r with the continuation
-- Arrs r b a.
-- Potentially, inline Union into Impure
data Eff r a where
Pure :: a -> Eff r a
Impure :: Union r x -> Arrs r x a -> Eff r a
-- | Application to the `generalized effectful function' Arrs r b w
qApp :: Arrs r b w -> b -> Eff r w
qApp q x =
case tviewl q of
TOne k -> k x
k :| t -> case k x of
Pure y -> qApp t y
Impure u q -> Impure u (q >< t)
-- | Compose effectful arrows (and possibly change the effect!)
qComp :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arr r' a c
qComp g h = h . qApp g
qComps :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arrs r' a c
qComps g h = tsingleton (qComp g h)
instance Functor (Eff r) where
fmap f (Pure x) = Pure (f x)
fmap f (Impure u q) = Impure u (q |> (Pure . f))
instance Applicative (Eff r) where
pure = Pure
Pure f <*> Pure x = Pure (f x)
Pure f <*> Impure u q = Impure u (q |> (Pure . f))
Impure u q <*> Pure x = Impure u (q |> (Pure . ($ x)))
Impure u q <*> m = Impure u (q |> (`fmap` m))
instance Monad (Eff r) where
Pure x >>= k = k x
Impure u q >>= k = Impure u (q |> k)
-- | send a request and wait for a reply
send :: Member t r => t v -> Eff r v
send t = Impure (inj t) (tsingleton Pure)
run :: Eff '[] w -> w
run (Pure x) = x
run _ = error "run: Impure should never happen"
-- the other case is unreachable since Union [] a cannot be
-- constructed.
-- Therefore, run is a total function if its argument terminates.
-- | Handler type
type Handler t r w = forall v. t v -> Arr r v w -> Eff r w
-- | Parameterized Handler type
type HandlerS s t r w = forall v. s -> t v -> (s -> Arr r v w) -> Eff r w
-- |
-- A convenient pattern: given a request (open union), either
-- handle it or relay it.
handleRelay :: (a -> Eff r w) -> Handler t r w -> Eff (t ': r) a -> Eff r w
handleRelay ret _ (Pure x) = ret x
handleRelay ret h (Impure u q) = case decomp u of
Right x -> h x k
Left u -> Impure u (tsingleton k)
where k = qComp q (handleRelay ret h)
-- | Parameterized handleRelay
handleRelayS :: s -> (s -> a -> Eff r w) -> HandlerS s t r w -> Eff (t ': r) a -> Eff r w
handleRelayS s ret _ (Pure x) = ret s x
handleRelayS s ret h (Impure u q) = case decomp u of
Right x -> h s x k
Left u -> Impure u (tsingleton (k s))
where k s x = handleRelayS s ret h (qApp q x)
-- Add something like Control.Exception.catches? It could be useful
-- for control with cut.
-- |
-- Intercept the request and possibly reply to it, but leave it unhandled
-- (that's why we use the same r all throuout)
interpose :: Member t r =>
(a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) ->
Eff r a -> Eff r w
interpose ret h (Pure x) = ret x
interpose ret h (Impure u q) = case prj u of
Just x -> h x k
_ -> Impure u (tsingleton k)
where k = qComp q (interpose ret h)