on master help sign in
Rename effect interpreters to effect handlers
48138ffAndrzej Rybczak
README.md+1−1
@@ -73,7 +73,7 @@ dedicated, well established solution such as
73
73
74This is where `effectful` comes in. The `Eff` monad it uses is essentially a
74This is where `effectful` comes in. The `Eff` monad it uses is essentially a
75`ReaderT` over `IO` on steroids, allowing us to dynamically extend its
75`ReaderT` over `IO` on steroids, allowing us to dynamically extend its
76−environment with data types that represent effects or their interpreters.
76+environment with data types that represent effects or their handlers.
77
77
78Because this concept is so simple:
78Because this concept is so simple:
79
79
effectful.cabal+1−1
@@ -87,11 +87,11 @@ library
87 Effectful.Async
87 Effectful.Async
88 Effectful.Error
88 Effectful.Error
89 Effectful.Fail
89 Effectful.Fail
90+ Effectful.Handler
90 Effectful.Internal.Effect
91 Effectful.Internal.Effect
91 Effectful.Internal.Env
92 Effectful.Internal.Env
92 Effectful.Internal.Monad
93 Effectful.Internal.Monad
93 Effectful.Internal.Unlift
94 Effectful.Internal.Unlift
94− Effectful.Interpreter
95 Effectful.Monad
95 Effectful.Monad
96 Effectful.Reader
96 Effectful.Reader
97 Effectful.Resource
97 Effectful.Resource
src/Effectful.hs+1−1
@@ -53,5 +53,5 @@ module Effectful
53 , localLiftUnliftIO
53 , localLiftUnliftIO
54 ) where
54 ) where
55
55
56−import Effectful.Interpreter
56+import Effectful.Handler
57import Effectful.Monad
57import Effectful.Monad
src/Effectful/Interpreter.hs → src/Effectful/Handler.hsrenamed+29−29
@@ -1,4 +1,4 @@
1−module Effectful.Interpreter
1+module Effectful.Handler
2 ( -- * Sending operations to the handler
2 ( -- * Sending operations to the handler
3 send
3 send
4
4
@@ -30,50 +30,50 @@ module Effectful.Interpreter
30 , localLiftUnliftIO
30 , localLiftUnliftIO
31 ) where
31 ) where
32
32
33−import Control.Exception
34import Control.Monad.IO.Unlift
33import Control.Monad.IO.Unlift
35import GHC.Stack
34import GHC.Stack
35+import qualified Control.Exception as E
36
36
37import Effectful.Internal.Effect
37import Effectful.Internal.Effect
38import Effectful.Internal.Env
38import Effectful.Internal.Env
39import Effectful.Internal.Monad
39import Effectful.Internal.Monad
40
40
41----------------------------------------
41----------------------------------------
42−-- Interpreter
42+-- Handler
43
43
44-- | Opaque representation of the 'Eff' environment at the point of calling the
44-- | Opaque representation of the 'Eff' environment at the point of calling the
45-- 'send' function, i.e. right before the control is passed to the effect
45-- 'send' function, i.e. right before the control is passed to the effect
46-- handler.
46-- handler.
47newtype LocalEnv es = LocalEnv (Env es)
47newtype LocalEnv es = LocalEnv (Env es)
48
48
49−data Interpreter (e :: Effect) = forall handlerEs. Interpreter
49+data Handler (e :: Effect) = forall handlerEs. Handler
50− { _env :: Env handlerEs
50+ { _env :: Env handlerEs
51− , _interpret :: forall a localEs. HasCallStack
51+ , _handle :: forall a localEs. HasCallStack
52− => LocalEnv localEs
52+ => LocalEnv localEs
53− -> e (Eff localEs) a
53+ -> e (Eff localEs) a
54− -> Eff handlerEs a
54+ -> Eff handlerEs a
55 }
55 }
56
56
57−runInterpreter :: Env es -> Interpreter e -> Eff (e : es) a -> IO a
57+runHandler :: Env es -> Handler e -> Eff (e : es) a -> IO a
58−runInterpreter es0 e m = do
58+runHandler es0 e m = do
59 size0 <- sizeEnv es0
59 size0 <- sizeEnv es0
60− bracket (unsafeConsEnv e relinker es0)
60+ E.bracket (unsafeConsEnv e relinker es0)
61− (unsafeTailEnv size0)
61+ (unsafeTailEnv size0)
62− (\es -> unEff m es)
62+ (\es -> unEff m es)
63 where
63 where
64− relinker :: Relinker Interpreter e
64+ relinker :: Relinker Handler e
65− relinker = Relinker $ \relink Interpreter{..} -> do
65+ relinker = Relinker $ \relink Handler{..} -> do
66 env <- relink _env
66 env <- relink _env
67− pure Interpreter { _env = env, .. }
67+ pure Handler { _env = env, .. }
68
68
69----------------------------------------
69----------------------------------------
70−-- Sending commands
70+-- Sending operations
71
71
72−-- | Send an operation of a given effect to the interpreter for execution.
72+-- | Send an operation of a given effect to its handler for execution.
73send :: (HasCallStack, e :> es) => e (Eff es) a -> Eff es a
73send :: (HasCallStack, e :> es) => e (Eff es) a -> Eff es a
74send op = unsafeEff $ \es -> do
74send op = unsafeEff $ \es -> do
75− Interpreter{..} <- getEnv es
75+ Handler{..} <- getEnv es
76− unEff (_interpret (LocalEnv es) op) _env
76+ unEff (_handle (LocalEnv es) op) _env
77
77
78----------------------------------------
78----------------------------------------
79-- Interpretation
79-- Interpretation
@@ -84,9 +84,9 @@ interpret
84 -- ^ The effect handler.
84 -- ^ The effect handler.
85 -> Eff (e : es) a
85 -> Eff (e : es) a
86 -> Eff es a
86 -> Eff es a
87−interpret interpreter m = unsafeEff $ \es -> do
87+interpret handler m = unsafeEff $ \es -> do
88 les <- forkEnv es
88 les <- forkEnv es
89− runInterpreter es (Interpreter les $ \_ -> interpreter) m
89+ runHandler es (Handler les $ \_ -> handler) m
90
90
91-- | Interpret a higher order effect.
91-- | Interpret a higher order effect.
92--
92--
@@ -97,9 +97,9 @@ interpretM
97 -- ^ The effect handler.
97 -- ^ The effect handler.
98 -> Eff (e : es) a
98 -> Eff (e : es) a
99 -> Eff es a
99 -> Eff es a
100−interpretM interpreter m = unsafeEff $ \es -> do
100+interpretM handler m = unsafeEff $ \es -> do
101 les <- forkEnv es
101 les <- forkEnv es
102− runInterpreter es (Interpreter les interpreter) m
102+ runHandler es (Handler les handler) m
103
103
104----------------------------------------
104----------------------------------------
105-- Reinterpretation
105-- Reinterpretation
@@ -112,10 +112,10 @@ reinterpret
112 -- ^ The effect handler.
112 -- ^ The effect handler.
113 -> Eff (e : es) a
113 -> Eff (e : es) a
114 -> Eff es b
114 -> Eff es b
115−reinterpret runHandlerEs interpreter m = unsafeEff $ \es -> do
115+reinterpret runHandlerEs handler m = unsafeEff $ \es -> do
116 les0 <- forkEnv es
116 les0 <- forkEnv es
117 (`unEff` les0) . runHandlerEs . unsafeEff $ \les -> do
117 (`unEff` les0) . runHandlerEs . unsafeEff $ \les -> do
118− runInterpreter es (Interpreter les $ \_ -> interpreter) m
118+ runHandler es (Handler les $ \_ -> handler) m
119
119
120-- | Interpret a higher order effect using other effects.
120-- | Interpret a higher order effect using other effects.
121--
121--
@@ -128,10 +128,10 @@ reinterpretM
128 -- ^ The effect handler.
128 -- ^ The effect handler.
129 -> Eff (e : es) a
129 -> Eff (e : es) a
130 -> Eff es b
130 -> Eff es b
131−reinterpretM runHandlerEs interpreter m = unsafeEff $ \es -> do
131+reinterpretM runHandlerEs handler m = unsafeEff $ \es -> do
132 les0 <- forkEnv es
132 les0 <- forkEnv es
133 (`unEff` les0) . runHandlerEs . unsafeEff $ \les -> do
133 (`unEff` les0) . runHandlerEs . unsafeEff $ \les -> do
134− runInterpreter es (Interpreter les interpreter) m
134+ runHandler es (Handler les handler) m
135
135
136----------------------------------------
136----------------------------------------
137-- Unlifts
137-- Unlifts
src/Effectful/Internal/Env.hs+24−13
@@ -43,7 +43,7 @@ type role Env nominal
43-- of kind 'Effect'.
43-- of kind 'Effect'.
44--
44--
45-- Supports forking, i.e. introduction of local branches for encapsulation of
45-- Supports forking, i.e. introduction of local branches for encapsulation of
46−-- data specific to effect interpreters.
46+-- data specific to effect handlers.
47--
47--
48-- Offers very good performance characteristics:
48-- Offers very good performance characteristics:
49--
49--
@@ -150,10 +150,10 @@ newForkId (ForkIdGen ref) = do
150
150
151newtype Relinker i (e :: Effect) where
151newtype Relinker i (e :: Effect) where
152 Relinker
152 Relinker
153− :: ((forall es. Env es -> IO (Env es)) -> i e -> IO (i e))
153+ :: ((forall es. Env es -> IO (Env es)) -> handler e -> IO (handler e))
154− -> Relinker i e
154+ -> Relinker handler e
155
155
156−noRelinker :: Relinker i e
156+noRelinker :: Relinker handler e
157noRelinker = Relinker $ \_ -> pure
157noRelinker = Relinker $ \_ -> pure
158
158
159----------------------------------------
159----------------------------------------
@@ -238,7 +238,7 @@ copyForks es fs len = \case
238
238
239type EnvRefCache = IORef (IM.IntMap (IORef EnvRef))
239type EnvRefCache = IORef (IM.IntMap (IORef EnvRef))
240
240
241−-- | Relink local environments hiding in the interpreters.
241+-- | Relink local environments hiding in the handlers.
242relinkData
242relinkData
243 :: IORef EnvRef
243 :: IORef EnvRef
244 -> ForkIdGen
244 -> ForkIdGen
@@ -294,7 +294,7 @@ cloneEnvRef gref gen cache fid lref0 = do
294
294
295----------------------------------------
295----------------------------------------
296
296
297−-- | Create a local fork of the environment for interpreters.
297+-- | Create a local fork of the environment for handlers.
298forkEnv :: Env es -> IO (Env es)
298forkEnv :: Env es -> IO (Env es)
299forkEnv env@(Env NoFork gref gen) = do
299forkEnv env@(Env NoFork gref gen) = do
300 size <- sizeEnv env
300 size <- sizeEnv env
@@ -321,7 +321,7 @@ sizeEnv (Env (Forks _ baseIx lref _) _ _) = do
321{-# NOINLINE sizeEnv #-}
321{-# NOINLINE sizeEnv #-}
322
322
323-- | Extract a specific data type from the environment.
323-- | Extract a specific data type from the environment.
324−getEnv :: forall e es i. e :> es => Env es -> IO (i e)
324+getEnv :: forall e es handler. e :> es => Env es -> IO (handler e)
325getEnv env = do
325getEnv env = do
326 (i, es) <- getLocation @e env
326 (i, es) <- getLocation @e env
327 fromAny <$> readSmallArray es i
327 fromAny <$> readSmallArray es i
@@ -343,7 +343,7 @@ checkSizeEnv k (Env (Forks _ baseIx lref _) _ _) = do
343-- Extending and shrinking
343-- Extending and shrinking
344
344
345-- | Extend the environment with a new data type (in place).
345-- | Extend the environment with a new data type (in place).
346−unsafeConsEnv :: i e -> Relinker i e -> Env es -> IO (Env (e : es))
346+unsafeConsEnv :: handler e -> Relinker handler e -> Env es -> IO (Env (e : es))
347unsafeConsEnv e f (Env fork gref gen) = case fork of
347unsafeConsEnv e f (Env fork gref gen) = case fork of
348 NoFork -> do
348 NoFork -> do
349 extendEnvRef gref
349 extendEnvRef gref
@@ -402,20 +402,31 @@ unsafeTailEnv len (Env fork gref gen) = case fork of
402-- Data retrieval and update
402-- Data retrieval and update
403
403
404-- | Replace the data type in the environment with a new value (in place).
404-- | Replace the data type in the environment with a new value (in place).
405−unsafePutEnv :: forall e es i. e :> es => i e -> Env es -> IO ()
405+unsafePutEnv
406+ :: forall e es handler. e :> es
407+ => handler e
408+ -> Env es -> IO ()
406unsafePutEnv e env = do
409unsafePutEnv e env = do
407 (i, es) <- getLocation @e env
410 (i, es) <- getLocation @e env
408 e `seq` writeSmallArray es i (toAny e)
411 e `seq` writeSmallArray es i (toAny e)
409
412
410-- | Modify the data type in the environment (in place).
413-- | Modify the data type in the environment (in place).
411−unsafeModifyEnv :: forall e es i. e :> es => (i e -> i e) -> Env es -> IO ()
414+unsafeModifyEnv
415+ :: forall e es handler. e :> es
416+ => (handler e -> handler e)
417+ -> Env es
418+ -> IO ()
412unsafeModifyEnv f env = do
419unsafeModifyEnv f env = do
413 (i, es) <- getLocation @e env
420 (i, es) <- getLocation @e env
414 e <- f . fromAny <$> readSmallArray es i
421 e <- f . fromAny <$> readSmallArray es i
415 e `seq` writeSmallArray es i (toAny e)
422 e `seq` writeSmallArray es i (toAny e)
416
423
417-- | Modify the data type in the environment (in place) and return a value.
424-- | Modify the data type in the environment (in place) and return a value.
418−unsafeStateEnv :: forall e es i a. e :> es => (i e -> (a, i e)) -> Env es -> IO a
425+unsafeStateEnv
426+ :: forall e es handler a. e :> es
427+ => (handler e -> (a, handler e))
428+ -> Env es
429+ -> IO a
419unsafeStateEnv f env = do
430unsafeStateEnv f env = do
420 (i, es) <- getLocation @e env
431 (i, es) <- getLocation @e env
421 (a, e) <- f . fromAny <$> readSmallArray es i
432 (a, e) <- f . fromAny <$> readSmallArray es i
@@ -443,8 +454,8 @@ getLocation (Env fork ref _) = do
443 -- - Most application code has no access to forks, in which case we look at
454 -- - Most application code has no access to forks, in which case we look at
444 -- the global EnvRef.
455 -- the global EnvRef.
445 --
456 --
446− -- - Interpreters will most likely access the newest fork for reinterpretation
457+ -- - Effect handlers will most likely access the newest fork with handler
447− -- of effects that are there.
458+ -- specific effects for reinterpretation.
448 case fork of
459 case fork of
449 NoFork -> pure (ix n, es)
460 NoFork -> pure (ix n, es)
450 Forks _ baseIx lref forks -> do
461 Forks _ baseIx lref forks -> do
src/Effectful/Internal/Monad.hs+9−9
@@ -390,46 +390,46 @@ unliftEff f = unliftStrategy >>= \case
390----------------------------------------
390----------------------------------------
391-- Helpers
391-- Helpers
392
392
393−runEffect :: i e -> Eff (e : es) a -> Eff es (a, i e)
393+runEffect :: handler e -> Eff (e : es) a -> Eff es (a, handler e)
394runEffect e0 m = unsafeEff $ \es0 -> do
394runEffect e0 m = unsafeEff $ \es0 -> do
395 size0 <- sizeEnv es0
395 size0 <- sizeEnv es0
396 bracket (unsafeConsEnv e0 noRelinker es0)
396 bracket (unsafeConsEnv e0 noRelinker es0)
397 (unsafeTailEnv size0)
397 (unsafeTailEnv size0)
398 (\es -> (,) <$> unEff m es <*> getEnv es)
398 (\es -> (,) <$> unEff m es <*> getEnv es)
399
399
400−evalEffect :: i e -> Eff (e : es) a -> Eff es a
400+evalEffect :: handler e -> Eff (e : es) a -> Eff es a
401evalEffect e m = unsafeEff $ \es0 -> do
401evalEffect e m = unsafeEff $ \es0 -> do
402 size0 <- sizeEnv es0
402 size0 <- sizeEnv es0
403 bracket (unsafeConsEnv e noRelinker es0)
403 bracket (unsafeConsEnv e noRelinker es0)
404 (unsafeTailEnv size0)
404 (unsafeTailEnv size0)
405 (\es -> unEff m es)
405 (\es -> unEff m es)
406
406
407−execEffect :: i e -> Eff (e : es) a -> Eff es (i e)
407+execEffect :: handler e -> Eff (e : es) a -> Eff es (handler e)
408execEffect e0 m = unsafeEff $ \es0 -> do
408execEffect e0 m = unsafeEff $ \es0 -> do
409 size0 <- sizeEnv es0
409 size0 <- sizeEnv es0
410 bracket (unsafeConsEnv e0 noRelinker es0)
410 bracket (unsafeConsEnv e0 noRelinker es0)
411 (unsafeTailEnv size0)
411 (unsafeTailEnv size0)
412 (\es -> unEff m es *> getEnv es)
412 (\es -> unEff m es *> getEnv es)
413
413
414−getEffect :: e :> es => Eff es (i e)
414+getEffect :: e :> es => Eff es (handler e)
415getEffect = unsafeEff $ \es -> getEnv es
415getEffect = unsafeEff $ \es -> getEnv es
416
416
417−putEffect :: e :> es => i e -> Eff es ()
417+putEffect :: e :> es => handler e -> Eff es ()
418putEffect e = unsafeEff $ \es -> unsafePutEnv e es
418putEffect e = unsafeEff $ \es -> unsafePutEnv e es
419
419
420−stateEffect :: e :> es => (i e -> (a, i e)) -> Eff es a
420+stateEffect :: e :> es => (handler e -> (a, handler e)) -> Eff es a
421stateEffect f = unsafeEff $ \es -> unsafeStateEnv f es
421stateEffect f = unsafeEff $ \es -> unsafeStateEnv f es
422
422
423−localEffect :: e :> es => (i e -> i e) -> Eff es a -> Eff es a
423+localEffect :: e :> es => (handler e -> handler e) -> Eff es a -> Eff es a
424localEffect f m = unsafeEff $ \es -> do
424localEffect f m = unsafeEff $ \es -> do
425 bracket (unsafeStateEnv (\e -> (e, f e)) es)
425 bracket (unsafeStateEnv (\e -> (e, f e)) es)
426 (\e -> unsafePutEnv e es)
426 (\e -> unsafePutEnv e es)
427 (\_ -> unEff m es)
427 (\_ -> unEff m es)
428
428
429−readerEffectM :: e :> es => (i e -> Eff es a) -> Eff es a
429+readerEffectM :: e :> es => (handler e -> Eff es a) -> Eff es a
430readerEffectM f = unsafeEff $ \es -> getEnv es >>= \e -> unEff (f e) es
430readerEffectM f = unsafeEff $ \es -> getEnv es >>= \e -> unEff (f e) es
431
431
432−stateEffectM :: e :> es => (i e -> Eff es (a, i e)) -> Eff es a
432+stateEffectM :: e :> es => (handler e -> Eff es (a, handler e)) -> Eff es a
433stateEffectM f = unsafeEff $ \es -> mask $ \release -> do
433stateEffectM f = unsafeEff $ \es -> mask $ \release -> do
434 (a, e) <- (\e -> release $ unEff (f e) es) =<< getEnv es
434 (a, e) <- (\e -> release $ unEff (f e) es) =<< getEnv es
435 unsafePutEnv e es
435 unsafePutEnv e es
src/Effectful/State/Dynamic.hs+1−1
@@ -33,7 +33,7 @@ module Effectful.State.Dynamic
33 , modifyM
33 , modifyM
34 ) where
34 ) where
35
35
36−import Effectful.Interpreter
36+import Effectful.Handler
37import Effectful.Monad
37import Effectful.Monad
38import qualified Effectful.State as SP
38import qualified Effectful.State as SP
39import qualified Effectful.State.MVar as SM
39import qualified Effectful.State.MVar as SM
src/Effectful/Writer/Dynamic.hs+1−1
@@ -15,7 +15,7 @@ module Effectful.Writer.Dynamic
15 , listens
15 , listens
16 ) where
16 ) where
17
17
18−import Effectful.Interpreter
18+import Effectful.Handler
19import Effectful.Monad
19import Effectful.Monad
20import qualified Effectful.Writer as WP
20import qualified Effectful.Writer as WP
21import qualified Effectful.Writer.MVar as WM
21import qualified Effectful.Writer.MVar as WM