on master help sign in
Less unsafe functions, document unsafeness
8f37f3fAndrzej Rybczak
effectful-core/src/Effectful/Handler.hs+14−14
@@ -120,7 +120,7 @@ localSeqUnlift
120 -- ^ Continuation with the unlifting function in scope.
120 -- ^ Continuation with the unlifting function in scope.
121 -> Eff es a
121 -> Eff es a
122localSeqUnlift (LocalEnv les) k = unsafeEff $ \es -> do
122localSeqUnlift (LocalEnv les) k = unsafeEff $ \es -> do
123− unsafeSeqUnliftEff les $ \unlift -> do
123+ seqUnliftEff les $ \unlift -> do
124 (`unEff` es) $ k $ unsafeEff_ . unlift
124 (`unEff` es) $ k $ unsafeEff_ . unlift
125
125
126-- | Create a local unlifting function with the 'SeqUnlift' strategy. For the
126-- | Create a local unlifting function with the 'SeqUnlift' strategy. For the
@@ -132,7 +132,7 @@ localSeqUnliftIO
132 -> ((forall r. Eff localEs r -> IO r) -> IO a)
132 -> ((forall r. Eff localEs r -> IO r) -> IO a)
133 -- ^ Continuation with the unlifting function in scope.
133 -- ^ Continuation with the unlifting function in scope.
134 -> Eff es a
134 -> Eff es a
135−localSeqUnliftIO (LocalEnv les) k = liftIO $ unsafeSeqUnliftEff les k
135+localSeqUnliftIO (LocalEnv les) k = liftIO $ seqUnliftEff les k
136
136
137-- | Create a local unlifting function with the given strategy.
137-- | Create a local unlifting function with the given strategy.
138localUnlift
138localUnlift
@@ -145,10 +145,10 @@ localUnlift
145 -> Eff es a
145 -> Eff es a
146localUnlift (LocalEnv les) strategy k = case strategy of
146localUnlift (LocalEnv les) strategy k = case strategy of
147 SeqUnlift -> unsafeEff $ \es -> do
147 SeqUnlift -> unsafeEff $ \es -> do
148− unsafeSeqUnliftEff les $ \unlift -> do
148+ seqUnliftEff les $ \unlift -> do
149 (`unEff` es) $ k $ unsafeEff_ . unlift
149 (`unEff` es) $ k $ unsafeEff_ . unlift
150 ConcUnlift p l -> unsafeEff $ \es -> do
150 ConcUnlift p l -> unsafeEff $ \es -> do
151− unsafeConcUnliftEff les p l $ \unlift -> do
151+ concUnliftEff les p l $ \unlift -> do
152 (`unEff` es) $ k $ unsafeEff_ . unlift
152 (`unEff` es) $ k $ unsafeEff_ . unlift
153
153
154-- | Create a local unlifting function with the given strategy.
154-- | Create a local unlifting function with the given strategy.
@@ -161,8 +161,8 @@ localUnliftIO
161 -- ^ Continuation with the unlifting function in scope.
161 -- ^ Continuation with the unlifting function in scope.
162 -> Eff es a
162 -> Eff es a
163localUnliftIO (LocalEnv les) strategy k = case strategy of
163localUnliftIO (LocalEnv les) strategy k = case strategy of
164− SeqUnlift -> liftIO $ unsafeSeqUnliftEff les k
164+ SeqUnlift -> liftIO $ seqUnliftEff les k
165− ConcUnlift p l -> liftIO $ unsafeConcUnliftEff les p l k
165+ ConcUnlift p l -> liftIO $ concUnliftEff les p l k
166
166
167-- | Utility for lifting 'Eff' operations of type
167-- | Utility for lifting 'Eff' operations of type
168--
168--
@@ -181,7 +181,7 @@ withLiftMap
181 -> Eff es r
181 -> Eff es r
182withLiftMap k = unsafeEff $ \es -> do
182withLiftMap k = unsafeEff $ \es -> do
183 (`unEff` es) $ k $ \mapEff m -> unsafeEff $ \localEs -> do
183 (`unEff` es) $ k $ \mapEff m -> unsafeEff $ \localEs -> do
184− unsafeSeqUnliftEff localEs $ \unlift -> do
184+ seqUnliftEff localEs $ \unlift -> do
185 (`unEff` es) . mapEff . liftIO $ unlift m
185 (`unEff` es) . mapEff . liftIO $ unlift m
186
186
187-- | Utility for lifting 'IO' operations of type
187-- | Utility for lifting 'IO' operations of type
@@ -215,7 +215,7 @@ withLiftMapIO
215 -- ^ Continuation with the lifting function in scope.
215 -- ^ Continuation with the lifting function in scope.
216 -> Eff es r
216 -> Eff es r
217withLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
217withLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
218− unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
218+ seqUnliftEff es $ \unlift -> mapIO $ unlift m
219
219
220----------------------------------------
220----------------------------------------
221-- Bidirectional lifts
221-- Bidirectional lifts
@@ -237,12 +237,12 @@ localLiftUnlift
237 -> Eff es a
237 -> Eff es a
238localLiftUnlift (LocalEnv les) strategy k = case strategy of
238localLiftUnlift (LocalEnv les) strategy k = case strategy of
239 SeqUnlift -> unsafeEff $ \es -> do
239 SeqUnlift -> unsafeEff $ \es -> do
240− unsafeSeqUnliftEff es $ \unliftEs -> do
240+ seqUnliftEff es $ \unliftEs -> do
241− unsafeSeqUnliftEff les $ \unliftLocalEs -> do
241+ seqUnliftEff les $ \unliftLocalEs -> do
242 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
242 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
243 ConcUnlift p l -> unsafeEff $ \es -> do
243 ConcUnlift p l -> unsafeEff $ \es -> do
244− unsafeConcUnliftEff es p l $ \unliftEs -> do
244+ concUnliftEff es p l $ \unliftEs -> do
245− unsafeConcUnliftEff les p l $ \unliftLocalEs -> do
245+ concUnliftEff les p l $ \unliftLocalEs -> do
246 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
246 (`unEff` es) $ k (unsafeEff_ . unliftEs) (liftIO . unliftLocalEs)
247
247
248-- | Create a local unlifting function with the given strategy along with an
248-- | Create a local unlifting function with the given strategy along with an
@@ -262,8 +262,8 @@ localLiftUnliftIO
262 -- ^ Continuation with the lifting and unlifting function in scope.
262 -- ^ Continuation with the lifting and unlifting function in scope.
263 -> Eff es a
263 -> Eff es a
264localLiftUnliftIO (LocalEnv les) strategy k = case strategy of
264localLiftUnliftIO (LocalEnv les) strategy k = case strategy of
265− SeqUnlift -> liftIO $ unsafeSeqUnliftEff les $ k unsafeEff_
265+ SeqUnlift -> liftIO $ seqUnliftEff les $ k unsafeEff_
266− ConcUnlift p l -> liftIO $ unsafeConcUnliftEff les p l $ k unsafeEff_
266+ ConcUnlift p l -> liftIO $ concUnliftEff les p l $ k unsafeEff_
267
267
268-- $setup
268-- $setup
269-- >>> import Control.Concurrent
269-- >>> import Control.Concurrent
effectful-core/src/Effectful/Internal/Env.hs+5−5
@@ -342,9 +342,9 @@ checkSizeEnv k (Env (Forks _ baseIx lref _) _ _) = do
342
342
343-- | Extend the environment with a new data type (in place).
343-- | Extend the environment with a new data type (in place).
344--
344--
345−-- /Note:/ this function is __unsafe__ because it renders the input 'Env'
345+-- This function is __highly unsafe__ because it renders the input 'Env'
346−-- unusable until the corresponding 'unsafeTailEnv' call, but it's not checked
346+-- unusable until the corresponding 'unsafeTailEnv' call is made, but it's not
347−-- anywhere.
347+-- checked anywhere.
348unsafeConsEnv :: handler e -> Relinker handler e -> Env es -> IO (Env (e : es))
348unsafeConsEnv :: handler e -> Relinker handler e -> Env es -> IO (Env (e : es))
349unsafeConsEnv e f (Env fork gref gen) = case fork of
349unsafeConsEnv e f (Env fork gref gen) = case fork of
350 NoFork -> do
350 NoFork -> do
@@ -381,11 +381,11 @@ unsafeConsEnv e f (Env fork gref gen) = case fork of
381-- | Shrink the environment by one data type (in place). Makes sure the size of
381-- | Shrink the environment by one data type (in place). Makes sure the size of
382-- the environment is as expected.
382-- the environment is as expected.
383--
383--
384−-- /Note:/ this function is __unsafe__ because it renders the input 'Env'
384+-- This function is __highly unsafe__ because it renders the input 'Env'
385-- unusable, but it's not checked anywhere.
385-- unusable, but it's not checked anywhere.
386unsafeTailEnv :: Int -> Env (e : es) -> IO ()
386unsafeTailEnv :: Int -> Env (e : es) -> IO ()
387unsafeTailEnv len (Env fork gref _) = case fork of
387unsafeTailEnv len (Env fork gref _) = case fork of
388− NoFork -> shrinkEnvRef len gref
388+ NoFork -> shrinkEnvRef len gref
389 Forks _ baseIx lref _ -> shrinkEnvRef (len - baseIx) lref
389 Forks _ baseIx lref _ -> shrinkEnvRef (len - baseIx) lref
390 where
390 where
391 shrinkEnvRef :: Int -> IORef EnvRef -> IO ()
391 shrinkEnvRef :: Int -> IORef EnvRef -> IO ()
effectful-core/src/Effectful/Internal/Monad.hs+25−16
@@ -37,8 +37,8 @@ module Effectful.Internal.Monad
37
37
38 --- *** Low-level helpers
38 --- *** Low-level helpers
39 , unsafeWithLiftMapIO
39 , unsafeWithLiftMapIO
40− , unsafeSeqUnliftEff
40+ , seqUnliftEff
41− , unsafeConcUnliftEff
41+ , concUnliftEff
42
42
43 -- * Primitive effects
43 -- * Primitive effects
44
44
@@ -126,10 +126,16 @@ unEff :: Eff es a -> Env es -> IO a
126unEff (Eff m) = m
126unEff (Eff m) = m
127
127
128-- | Access the underlying 'IO' monad along with the environment.
128-- | Access the underlying 'IO' monad along with the environment.
129+--
130+-- This function is __unsafe__ because it can be used to introduce arbitrary
131+-- 'IO' actions into pure 'Eff' operations.
129unsafeEff :: (Env es -> IO a) -> Eff es a
132unsafeEff :: (Env es -> IO a) -> Eff es a
130unsafeEff m = Eff (oneShot m)
133unsafeEff m = Eff (oneShot m)
131
134
132-- | Access the underlying 'IO' monad.
135-- | Access the underlying 'IO' monad.
136+--
137+-- This function is __unsafe__ because it can be used to introduce arbitrary
138+-- 'IO' actions into pure 'Eff' operations.
133unsafeEff_ :: IO a -> Eff es a
139unsafeEff_ :: IO a -> Eff es a
134unsafeEff_ m = unsafeEff $ \_ -> m
140unsafeEff_ m = unsafeEff $ \_ -> m
135
141
@@ -141,6 +147,9 @@ unsafeEff_ m = unsafeEff $ \_ -> m
141--
147--
142-- @forall localEs. 'Eff' localEs a -> 'Eff' localEs b@
148-- @forall localEs. 'Eff' localEs a -> 'Eff' localEs b@
143--
149--
150+-- This function is __unsafe__ because it can be used to introduce arbitrary
151+-- 'IO' actions into pure 'Eff' operations.
152+--
144-- /Note:/ the 'IO' operation must not run its argument in a separate thread,
153-- /Note:/ the 'IO' operation must not run its argument in a separate thread,
145-- attempting to do so will result in a runtime error.
154-- attempting to do so will result in a runtime error.
146unsafeWithLiftMapIO
155unsafeWithLiftMapIO
@@ -148,15 +157,15 @@ unsafeWithLiftMapIO
148 => ((forall a b localEs. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
157 => ((forall a b localEs. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
149 -> Eff es r
158 -> Eff es r
150unsafeWithLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
159unsafeWithLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
151− unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
160+ seqUnliftEff es $ \unlift -> mapIO $ unlift m
152
161
153-- | Lower 'Eff' operations into 'IO' ('SeqUnlift').
162-- | Lower 'Eff' operations into 'IO' ('SeqUnlift').
154−unsafeSeqUnliftEff
163+seqUnliftEff
155 :: HasCallStack
164 :: HasCallStack
156 => Env es
165 => Env es
157 -> ((forall r. Eff es r -> IO r) -> IO a)
166 -> ((forall r. Eff es r -> IO r) -> IO a)
158 -> IO a
167 -> IO a
159−unsafeSeqUnliftEff es k = do
168+seqUnliftEff es k = do
160 tid0 <- myThreadId
169 tid0 <- myThreadId
161 k $ \m -> do
170 k $ \m -> do
162 tid <- myThreadId
171 tid <- myThreadId
@@ -167,21 +176,21 @@ unsafeSeqUnliftEff es k = do
167 ++ "in multiple threads, have a look at UnliftStrategy (ConcUnlift)."
176 ++ "in multiple threads, have a look at UnliftStrategy (ConcUnlift)."
168
177
169-- | Lower 'Eff' operations into 'IO' ('ConcUnlift').
178-- | Lower 'Eff' operations into 'IO' ('ConcUnlift').
170−unsafeConcUnliftEff
179+concUnliftEff
171 :: HasCallStack
180 :: HasCallStack
172 => Env es
181 => Env es
173 -> Persistence
182 -> Persistence
174 -> Limit
183 -> Limit
175 -> ((forall r. Eff es r -> IO r) -> IO a)
184 -> ((forall r. Eff es r -> IO r) -> IO a)
176 -> IO a
185 -> IO a
177−unsafeConcUnliftEff es Ephemeral (Limited uses) k =
186+concUnliftEff es Ephemeral (Limited uses) k =
178− unsafeEphemeralConcUnliftIO uses k es unEff
187+ ephemeralConcUnliftIO uses k es unEff
179−unsafeConcUnliftEff es Ephemeral Unlimited k =
188+concUnliftEff es Ephemeral Unlimited k =
180− unsafeEphemeralConcUnliftIO maxBound k es unEff
189+ ephemeralConcUnliftIO maxBound k es unEff
181−unsafeConcUnliftEff es Persistent (Limited threads) k =
190+concUnliftEff es Persistent (Limited threads) k =
182− unsafePersistentConcUnliftIO False threads k es unEff
191+ persistentConcUnliftIO False threads k es unEff
183−unsafeConcUnliftEff es Persistent Unlimited k =
192+concUnliftEff es Persistent Unlimited k =
184− unsafePersistentConcUnliftIO True maxBound k es unEff
193+ persistentConcUnliftIO True maxBound k es unEff
185
194
186----------------------------------------
195----------------------------------------
187-- Base
196-- Base
@@ -400,9 +409,9 @@ withEffToIO
400 -- ^ Continuation with the unlifting function in scope.
409 -- ^ Continuation with the unlifting function in scope.
401 -> Eff es a
410 -> Eff es a
402withEffToIO f = unliftStrategy >>= \case
411withEffToIO f = unliftStrategy >>= \case
403− SeqUnlift -> unsafeEff $ \es -> unsafeSeqUnliftEff es f
412+ SeqUnlift -> unsafeEff $ \es -> seqUnliftEff es f
404 ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
413 ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
405− unsafeEff $ \es -> unsafeConcUnliftEff es p b f
414+ unsafeEff $ \es -> concUnliftEff es p b f
406
415
407----------------------------------------
416----------------------------------------
408-- Helpers
417-- Helpers
effectful-core/src/Effectful/Internal/Unlift.hs+6−6
@@ -6,8 +6,8 @@
6-- This module is intended for internal use only, and may change without warning
6-- This module is intended for internal use only, and may change without warning
7-- in subsequent releases.
7-- in subsequent releases.
8module Effectful.Internal.Unlift
8module Effectful.Internal.Unlift
9− ( unsafeEphemeralConcUnliftIO
9+ ( ephemeralConcUnliftIO
10− , unsafePersistentConcUnliftIO
10+ , persistentConcUnliftIO
11 ) where
11 ) where
12
12
13import Control.Concurrent
13import Control.Concurrent
@@ -25,14 +25,14 @@ import Effectful.Internal.Utils
25
25
26-- | Concurrent unlift that doesn't preserve the environment between calls to
26-- | Concurrent unlift that doesn't preserve the environment between calls to
27-- the unlifting function in threads other than its creator.
27-- the unlifting function in threads other than its creator.
28−unsafeEphemeralConcUnliftIO
28+ephemeralConcUnliftIO
29 :: HasCallStack
29 :: HasCallStack
30 => Int
30 => Int
31 -> ((forall r. m r -> IO r) -> IO a)
31 -> ((forall r. m r -> IO r) -> IO a)
32 -> Env es
32 -> Env es
33 -> (forall r. m r -> Env es -> IO r)
33 -> (forall r. m r -> Env es -> IO r)
34 -> IO a
34 -> IO a
35−unsafeEphemeralConcUnliftIO uses k es0 unEff = do
35+ephemeralConcUnliftIO uses k es0 unEff = do
36 unless (uses > 0) $ do
36 unless (uses > 0) $ do
37 error $ "Invalid number of uses: " ++ show uses
37 error $ "Invalid number of uses: " ++ show uses
38 tid0 <- myThreadId
38 tid0 <- myThreadId
@@ -58,7 +58,7 @@ unsafeEphemeralConcUnliftIO uses k es0 unEff = do
58
58
59-- | Concurrent unlift that preserves the environment between calls to the
59-- | Concurrent unlift that preserves the environment between calls to the
60-- unlifting function within a particular thread.
60-- unlifting function within a particular thread.
61−unsafePersistentConcUnliftIO
61+persistentConcUnliftIO
62 :: HasCallStack
62 :: HasCallStack
63 => Bool
63 => Bool
64 -> Int
64 -> Int
@@ -66,7 +66,7 @@ unsafePersistentConcUnliftIO
66 -> Env es
66 -> Env es
67 -> (forall r. m r -> Env es -> IO r)
67 -> (forall r. m r -> Env es -> IO r)
68 -> IO a
68 -> IO a
69−unsafePersistentConcUnliftIO cleanUp threads k es0 unEff = do
69+persistentConcUnliftIO cleanUp threads k es0 unEff = do
70 unless (threads > 0) $ do
70 unless (threads > 0) $ do
71 error $ "Invalid number of threads: " ++ show threads
71 error $ "Invalid number of threads: " ++ show threads
72 tid0 <- myThreadId
72 tid0 <- myThreadId