Split Effectful.Dispatch.Static into different modules

This commit is contained in:
Andrzej Rybczak 2022-02-12 00:01:11 +01:00
parent eef830f5aa
commit cc25dc9ef4
20 changed files with 204 additions and 99 deletions

View File

@ -82,6 +82,8 @@ library
exposed-modules: Effectful exposed-modules: Effectful
Effectful.Dispatch.Dynamic Effectful.Dispatch.Dynamic
Effectful.Dispatch.Static Effectful.Dispatch.Static
Effectful.Dispatch.Static.Primitive
Effectful.Dispatch.Static.Unsafe
Effectful.Error.Dynamic Effectful.Error.Dynamic
Effectful.Error.Static Effectful.Error.Static
Effectful.Fail Effectful.Fail

View File

@ -356,7 +356,7 @@ localUnliftIO (LocalEnv les) strategy k = case strategy of
-- --
-- @'Eff' localEs a -> 'Eff' localEs b@ -- @'Eff' localEs a -> 'Eff' localEs b@
-- --
-- /Note:/ the computation must not run its argument in a separate thread, -- /Note:/ the computation must not run its argument in a different thread,
-- attempting to do so will result in a runtime error. -- attempting to do so will result in a runtime error.
withLiftMap withLiftMap
:: (HasCallStack, SuffixOf es handlerEs) :: (HasCallStack, SuffixOf es handlerEs)
@ -380,7 +380,7 @@ withLiftMap !_ k = unsafeEff $ \es -> do
-- --
-- @'Eff' localEs a -> 'Eff' localEs b@ -- @'Eff' localEs a -> 'Eff' localEs b@
-- --
-- /Note:/ the computation must not run its argument in a separate thread, -- /Note:/ the computation must not run its argument in a different thread,
-- attempting to do so will result in a runtime error. -- attempting to do so will result in a runtime error.
-- --
-- Useful e.g. for lifting the unmasking function in -- Useful e.g. for lifting the unmasking function in

View File

@ -24,41 +24,18 @@ module Effectful.Dispatch.Static
-- ** Unlifts -- ** Unlifts
, seqUnliftIO , seqUnliftIO
, concUnliftIO , concUnliftIO
, unsafeSeqUnliftIO
, unsafeConcUnliftIO
-- ** Utils -- ** Utils
, unEff , unEff
, unsafeEff , unsafeEff
, unsafeEff_ , unsafeEff_
, unsafeLiftMapIO , unsafeLiftMapIO
, unsafeUnliftIO
-- * Primitive API
, Env
, Relinker(..)
, dummyRelinker
-- ** Representation of effects
, EffectRep
-- ** Operations
, emptyEnv
, cloneEnv
, forkEnv
, sizeEnv
, checkSizeEnv
-- ** Extending and shrinking
, unsafeConsEnv
, unsafeTailEnv
-- ** Data retrieval and update
, getEnv
, putEnv
, stateEnv
, modifyEnv
) where ) where
import Effectful.Internal.Env import GHC.Stack (HasCallStack)
import Effectful.Internal.Monad import Effectful.Internal.Monad
-- $intro -- $intro
@ -180,27 +157,40 @@ import Effectful.Internal.Monad
-- --
-- @'Eff' es a -> 'Eff' es b@ -- @'Eff' es a -> 'Eff' es b@
-- --
-- This function is __unsafe__ because: -- /Note:/ the computation must not run its argument in a separate thread,
-- attempting to do so will result in a runtime error.
-- --
-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff' -- This function is __unsafe__ because it can be used to introduce arbitrary
-- computations. -- 'IO' actions into pure 'Eff' computations.
-- unsafeLiftMapIO :: HasCallStack => (IO a -> IO b) -> Eff es a -> Eff es b
-- - The 'IO' computation must not run its argument in a separate thread, but unsafeLiftMapIO f m = unsafeEff $ \es -> do
-- it's not checked anywhere. seqUnliftIO es $ \unlift -> f (unlift m)
unsafeLiftMapIO :: (IO a -> IO b) -> Eff es a -> Eff es b
unsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)
-- | Utility for running 'Eff' computations locally in the 'IO' monad. -- | Create an unlifting function with the 'SeqUnlift' strategy.
-- --
-- This function is __unsafe__ because: -- This function is __unsafe__ because it can be used to introduce arbitrary
-- 'IO' actions into pure 'Eff' computations.
unsafeSeqUnliftIO
:: HasCallStack
=> ((forall r. Eff es r -> IO r) -> IO a)
-- ^ Continuation with the unlifting function in scope.
-> Eff es a
unsafeSeqUnliftIO k = unsafeEff $ \es -> do
seqUnliftIO es k
-- | Create an unlifting function with the 'ConcUnlift' strategy.
-- --
-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff' -- This function is __unsafe__ because it can be used to introduce arbitrary
-- computations. -- 'IO' actions into pure 'Eff' computations.
-- unsafeConcUnliftIO
-- - Unlifted 'Eff' computations must not be run in a thread distinct from the :: HasCallStack
-- caller of 'unsafeUnliftIO', but it's not checked anywhere. => Persistence
unsafeUnliftIO :: ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a -> Limit
unsafeUnliftIO k = unsafeEff $ \es -> k (`unEff` es) -> ((forall r. Eff es r -> IO r) -> IO a)
-- ^ Continuation with the unlifting function in scope.
-> Eff es a
unsafeConcUnliftIO persistence limit k = unsafeEff $ \es -> do
concUnliftIO es persistence limit k
-- $setup -- $setup
-- >>> import Effectful -- >>> import Effectful

View File

@ -0,0 +1,36 @@
-- | Primitive API for statically dispatched effects.
--
-- /Warning:/ this module exposes internal implementation details of the 'Eff'
-- monad. Most of the time functions from "Effectful.Dispatch.Static" are
-- sufficient and safer to use.
module Effectful.Dispatch.Static.Primitive
( -- * The environment
Env
-- ** Relinker
, Relinker(..)
, dummyRelinker
-- ** Representation of effects
, EffectRep
-- ** Extending and shrinking
, unsafeConsEnv
, unsafeTailEnv
-- ** Data retrieval and update
, getEnv
, putEnv
, stateEnv
, modifyEnv
-- ** Utils
, emptyEnv
, cloneEnv
, forkEnv
, sizeEnv
, checkSizeEnv
) where
import Effectful.Internal.Env
import Effectful.Internal.Monad

View File

@ -0,0 +1,40 @@
module Effectful.Dispatch.Static.Unsafe
( reallyUnsafeLiftMapIO
, reallyUnsafeUnliftIO
) where
import Effectful.Internal.Monad
-- | Utility for lifting 'IO' computations of type
--
-- @'IO' a -> 'IO' b@
--
-- to
--
-- @'Eff' es a -> 'Eff' es b@
--
-- This function is __highly unsafe__ because:
--
-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'
-- computations.
--
-- - The 'IO' computation must not run its argument in a different thread, but
-- it's not checked anywhere.
--
-- __If you disregard the second point, segmentation faults await.__
reallyUnsafeLiftMapIO :: (IO a -> IO b) -> Eff es a -> Eff es b
reallyUnsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)
-- | Create an unlifting function.
--
-- This function is __highly unsafe__ because:
--
-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'
-- computations.
--
-- - Unlifted 'Eff' computations must not be run in a thread distinct from the
-- caller of 'reallyUnsafeUnliftIO', but it's not checked anywhere.
--
-- __If you disregard the second point, segmentation faults await.__
reallyUnsafeUnliftIO :: ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a
reallyUnsafeUnliftIO k = unsafeEff $ \es -> k (`unEff` es)

View File

@ -102,6 +102,7 @@ import GHC.Stack
import Effectful import Effectful
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Internal.Utils import Effectful.Internal.Utils
-- | Provide the ability to handle errors of type @e@. -- | Provide the ability to handle errors of type @e@.

View File

@ -29,7 +29,7 @@ module Effectful.Internal.Env
, checkSizeEnv , checkSizeEnv
-- ** Extending and shrinking -- ** Extending and shrinking
, veryUnsafeConsEnv , reallyUnsafeConsEnv
, unsafeTailEnv , unsafeTailEnv
-- ** Data retrieval and update -- ** Data retrieval and update
@ -52,12 +52,17 @@ import Effectful.Internal.Utils
type role Env nominal type role Env nominal
-- | A strict (WHNF), thread local, mutable, extensible record indexed by types -- | A strict (WHNF), __thread local__, mutable, extensible record indexed by types
-- of kind 'Effect'. -- of kind 'Effect'.
-- --
-- Supports forking, i.e. introduction of local branches for encapsulation of -- Supports forking, i.e. introduction of local branches for encapsulation of
-- data specific to effect handlers. -- data specific to effect handlers.
-- --
-- __Warning: the environment is a mutable data structure and cannot be simultaneously used from multiple threads under any circumstances.__
--
-- In order to pass it to a different thread, you need to perform a deep copy
-- with the 'cloneEnv' funtion.
--
-- Offers very good performance characteristics: -- Offers very good performance characteristics:
-- --
-- - Extending: /O(1)/ (amortized). -- - Extending: /O(1)/ (amortized).
@ -68,6 +73,7 @@ type role Env nominal
-- --
-- - Modification of a specific element: /O(1)/. -- - Modification of a specific element: /O(1)/.
-- --
--
-- Here's an example of how the environment might look: -- Here's an example of how the environment might look:
-- --
-- @ -- @
@ -182,6 +188,8 @@ emptyEnv :: IO (Env '[])
emptyEnv = Env NoFork <$> emptyEnvRef <*> newForkIdGen emptyEnv = Env NoFork <$> emptyEnvRef <*> newForkIdGen
-- | Clone the environment. -- | Clone the environment.
--
-- Mostly used to pass the environment to a different thread.
cloneEnv :: Env es -> IO (Env es) cloneEnv :: Env es -> IO (Env es)
cloneEnv (Env NoFork gref0 gen0) = do cloneEnv (Env NoFork gref0 gen0) = do
EnvRef n es0 fs0 <- readIORef gref0 EnvRef n es0 fs0 <- readIORef gref0
@ -361,10 +369,12 @@ checkSizeEnv k (Env (Forks _ baseIx lref _) _ _) = do
-- - The @rep@ type variable is unrestricted, so it's possible to put in a -- - The @rep@ type variable is unrestricted, so it's possible to put in a
-- different data type than the one retrieved later. -- different data type than the one retrieved later.
-- --
-- - It renders the input 'Env' unusable until the corresponding 'unsafeTailEnv' -- - It renders the input 'Env' __unusable__ until the corresponding
-- call is made, but it's not checked anywhere. -- 'unsafeTailEnv' call is made, but it's not checked anywhere.
veryUnsafeConsEnv :: rep e -> Relinker rep e -> Env es -> IO (Env (e : es)) --
veryUnsafeConsEnv e f (Env fork gref gen) = case fork of -- __If you disregard the above, segmentation faults await.__
reallyUnsafeConsEnv :: rep e -> Relinker rep e -> Env es -> IO (Env (e : es))
reallyUnsafeConsEnv e f (Env fork gref gen) = case fork of
NoFork -> do NoFork -> do
extendEnvRef gref extendEnvRef gref
pure $ Env NoFork gref gen pure $ Env NoFork gref gen
@ -394,13 +404,15 @@ veryUnsafeConsEnv e f (Env fork gref gen) = case fork of
doubleCapacity :: Int -> Int doubleCapacity :: Int -> Int
doubleCapacity n = max 1 n * 2 doubleCapacity n = max 1 n * 2
{-# NOINLINE veryUnsafeConsEnv #-} {-# NOINLINE reallyUnsafeConsEnv #-}
-- | Shrink the environment by one data type (in place). Makes sure the size of -- | Shrink the environment by one data type (in place). Makes sure the size of
-- the environment is as expected. -- the environment is as expected.
-- --
-- This function is __highly unsafe__ because it renders the input 'Env' -- This function is __highly unsafe__ because it renders the input 'Env'
-- unusable, but it's not checked anywhere. -- __unusable__, but it's not checked anywhere.
--
-- __If you disregard the above, segmentation faults await.__
unsafeTailEnv :: Int -> Env (e : es) -> IO () unsafeTailEnv :: Int -> Env (e : es) -> IO ()
unsafeTailEnv len (Env fork gref _) = case fork of unsafeTailEnv len (Env fork gref _) = case fork of
NoFork -> shrinkEnvRef len gref NoFork -> shrinkEnvRef len gref

View File

@ -475,13 +475,15 @@ localStaticRep f m = unsafeEff $ \es -> do
-- This function is __highly unsafe__ because it renders the input 'Env' -- This function is __highly unsafe__ because it renders the input 'Env'
-- unusable until the corresponding 'unsafeTailEnv' call is made, but it's not -- unusable until the corresponding 'unsafeTailEnv' call is made, but it's not
-- checked anywhere. -- checked anywhere.
--
-- __If you disregard the above, segmentation faults await.__
unsafeConsEnv unsafeConsEnv
:: EffectRep (DispatchOf e) e :: EffectRep (DispatchOf e) e
-- ^ The representation of the effect. -- ^ The representation of the effect.
-> Relinker (EffectRep (DispatchOf e)) e -> Relinker (EffectRep (DispatchOf e)) e
-> Env es -> Env es
-> IO (Env (e : es)) -> IO (Env (e : es))
unsafeConsEnv = veryUnsafeConsEnv unsafeConsEnv = reallyUnsafeConsEnv
-- | Extract a specific representation of the effect from the environment. -- | Extract a specific representation of the effect from the environment.
getEnv :: e :> es => Env es -> IO (EffectRep (DispatchOf e) e) getEnv :: e :> es => Env es -> IO (EffectRep (DispatchOf e) e)

View File

@ -45,6 +45,7 @@ import Control.Concurrent.MVar
import Effectful import Effectful
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
-- | Provide access to a strict (WHNF), shared, mutable value of type @s@. -- | Provide access to a strict (WHNF), shared, mutable value of type @s@.
data State s :: Effect data State s :: Effect

View File

@ -31,6 +31,7 @@ import Control.Exception (onException, mask)
import Effectful import Effectful
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
-- | Provide access to a strict (WHNF), thread local, write only value of type -- | Provide access to a strict (WHNF), thread local, write only value of type
-- @w@. -- @w@.

View File

@ -32,6 +32,7 @@ import Control.Exception (onException, uninterruptibleMask)
import Effectful import Effectful
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
-- | Provide access to a strict (WHNF), shared, write only value of type @w@. -- | Provide access to a strict (WHNF), shared, write only value of type @w@.
data Writer w :: Effect data Writer w :: Effect

View File

@ -70,6 +70,8 @@ import qualified GHC.Conc as GHC
import Effectful import Effectful
import Effectful.Concurrent.Effect import Effectful.Concurrent.Effect
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Dispatch.Static.Unsafe
---------------------------------------- ----------------------------------------
-- Basic concurrency operations -- Basic concurrency operations
@ -99,9 +101,7 @@ forkIOWithUnmask
:: Concurrent :> es :: Concurrent :> es
=> ((forall a. Eff es a -> Eff es a) -> Eff es ()) => ((forall a. Eff es a -> Eff es a) -> Eff es ())
-> Eff es C.ThreadId -> Eff es C.ThreadId
forkIOWithUnmask f = unsafeEff $ \es -> do forkIOWithUnmask = liftForkWithUnmask C.forkIOWithUnmask
esF <- cloneEnv es
C.forkIOWithUnmask $ \unmask -> unEff (f $ unsafeLiftMapIO unmask) esF
-- | Lifted 'C.killThread'. -- | Lifted 'C.killThread'.
killThread :: Concurrent :> es => C.ThreadId -> Eff es () killThread :: Concurrent :> es => C.ThreadId -> Eff es ()
@ -126,9 +126,7 @@ forkOnWithUnmask
=> Int => Int
-> ((forall a. Eff es a -> Eff es a) -> Eff es ()) -> ((forall a. Eff es a -> Eff es a) -> Eff es ())
-> Eff es C.ThreadId -> Eff es C.ThreadId
forkOnWithUnmask n f = unsafeEff $ \es -> do forkOnWithUnmask n = liftForkWithUnmask (C.forkOnWithUnmask n)
esF <- cloneEnv es
C.forkOnWithUnmask n $ \unmask -> unEff (f $ unsafeLiftMapIO unmask) esF
-- | Lifted 'C.getNumCapabilities'. -- | Lifted 'C.getNumCapabilities'.
getNumCapabilities :: Concurrent :> es => Eff es Int getNumCapabilities :: Concurrent :> es => Eff es Int
@ -192,9 +190,7 @@ forkOSWithUnmask
:: Concurrent :> es :: Concurrent :> es
=> ((forall a. Eff es a -> Eff es a) -> Eff es ()) => ((forall a. Eff es a -> Eff es a) -> Eff es ())
-> Eff es C.ThreadId -> Eff es C.ThreadId
forkOSWithUnmask f = unsafeEff $ \es -> do forkOSWithUnmask = liftForkWithUnmask C.forkOSWithUnmask
esF <- cloneEnv es
C.forkOSWithUnmask $ \unmask -> unEff (f $ unsafeLiftMapIO unmask) esF
-- | Lifted 'C.isCurrentThreadBound'. -- | Lifted 'C.isCurrentThreadBound'.
isCurrentThreadBound :: Concurrent :> es => Eff es Bool isCurrentThreadBound :: Concurrent :> es => Eff es Bool
@ -218,3 +214,15 @@ runInUnboundThread k = unsafeEff $ \es -> do
-- | Lifted 'C.mkWeakThreadId'. -- | Lifted 'C.mkWeakThreadId'.
mkWeakThreadId :: Concurrent :> es => C.ThreadId -> Eff es (Weak C.ThreadId) mkWeakThreadId :: Concurrent :> es => C.ThreadId -> Eff es (Weak C.ThreadId)
mkWeakThreadId = unsafeEff_ . C.mkWeakThreadId mkWeakThreadId = unsafeEff_ . C.mkWeakThreadId
----------------------------------------
-- Helpers
liftForkWithUnmask
:: (((forall c. IO c -> IO c) -> IO a) -> IO C.ThreadId)
-> ((forall c. Eff es c -> Eff es c) -> Eff es a)
-> Eff es C.ThreadId
liftForkWithUnmask fork action = unsafeEff $ \es -> do
esF <- cloneEnv es
-- Unmask never runs its argument in a different thread.
fork $ \unmask -> unEff (action $ reallyUnsafeLiftMapIO unmask) esF

View File

@ -87,6 +87,8 @@ import qualified UnliftIO.Internals.Async as I
import Effectful import Effectful
import Effectful.Concurrent.Effect import Effectful.Concurrent.Effect
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Dispatch.Static.Unsafe
-- | Lifted 'A.async'. -- | Lifted 'A.async'.
async :: Concurrent :> es => Eff es a -> Eff es (Async a) async :: Concurrent :> es => Eff es a -> Eff es (Async a)
@ -524,7 +526,8 @@ liftAsyncWithUnmask
-> Eff es (Async a) -> Eff es (Async a)
liftAsyncWithUnmask fork action = unsafeEff $ \es -> do liftAsyncWithUnmask fork action = unsafeEff $ \es -> do
esA <- cloneEnv es esA <- cloneEnv es
fork $ \unmask -> unEff (action $ unsafeLiftMapIO unmask) esA -- Unmask never runs its argument in a different thread.
fork $ \unmask -> unEff (action $ reallyUnsafeLiftMapIO unmask) esA
liftWithAsync liftWithAsync
:: (IO a -> (Async a -> IO b) -> IO b) :: (IO a -> (Async a -> IO b) -> IO b)
@ -543,5 +546,6 @@ liftWithAsyncWithUnmask
-> Eff es b -> Eff es b
liftWithAsyncWithUnmask withA action k = unsafeEff $ \es -> do liftWithAsyncWithUnmask withA action k = unsafeEff $ \es -> do
esA <- cloneEnv es esA <- cloneEnv es
withA (\unmask -> unEff (action $ unsafeLiftMapIO unmask) esA) -- Unmask never runs its argument in a different thread.
withA (\unmask -> unEff (action $ reallyUnsafeLiftMapIO unmask) esA)
(\a -> unEff (k a) es) (\a -> unEff (k a) es)

View File

@ -34,6 +34,8 @@ import qualified Control.Concurrent.MVar as M
import Effectful import Effectful
import Effectful.Concurrent.Effect import Effectful.Concurrent.Effect
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
import Effectful.Dispatch.Static.Unsafe
-- | Lifted 'M.newEmptyMVar'. -- | Lifted 'M.newEmptyMVar'.
newEmptyMVar :: Concurrent :> es => Eff es (MVar a) newEmptyMVar :: Concurrent :> es => Eff es (MVar a)
@ -77,35 +79,36 @@ tryReadMVar = unsafeEff_ . M.tryReadMVar
-- | Lifted 'M.withMVar'. -- | Lifted 'M.withMVar'.
withMVar :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b withMVar :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
withMVar var f = unsafeUnliftIO $ \unlift -> do withMVar var f = reallyUnsafeUnliftIO $ \unlift -> do
M.withMVar var $ unlift . f M.withMVar var $ unlift . f
-- | Lifted 'M.withMVarMasked'. -- | Lifted 'M.withMVarMasked'.
withMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b withMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es b) -> Eff es b
withMVarMasked var f = unsafeUnliftIO $ \unlift -> do withMVarMasked var f = reallyUnsafeUnliftIO $ \unlift -> do
M.withMVarMasked var $ unlift . f M.withMVarMasked var $ unlift . f
-- | Lifted 'M.modifyMVar_'. -- | Lifted 'M.modifyMVar_'.
modifyMVar_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es () modifyMVar_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVar_ var f = unsafeUnliftIO $ \unlift -> do modifyMVar_ var f = reallyUnsafeUnliftIO $ \unlift -> do
M.modifyMVar_ var $ unlift . f M.modifyMVar_ var $ unlift . f
-- | Lifted 'M.modifyMVar'. -- | Lifted 'M.modifyMVar'.
modifyMVar :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b modifyMVar :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVar var f = unsafeUnliftIO $ \unlift -> do modifyMVar var f = reallyUnsafeUnliftIO $ \unlift -> do
M.modifyMVar var $ unlift . f M.modifyMVar var $ unlift . f
-- | Lifted 'M.modifyMVarMasked_'. -- | Lifted 'M.modifyMVarMasked_'.
modifyMVarMasked_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es () modifyMVarMasked_ :: Concurrent :> es => MVar a -> (a -> Eff es a) -> Eff es ()
modifyMVarMasked_ var f = unsafeUnliftIO $ \unlift -> do modifyMVarMasked_ var f = reallyUnsafeUnliftIO $ \unlift -> do
M.modifyMVarMasked_ var $ unlift . f M.modifyMVarMasked_ var $ unlift . f
-- | Lifted 'M.modifyMVarMasked'. -- | Lifted 'M.modifyMVarMasked'.
modifyMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b modifyMVarMasked :: Concurrent :> es => MVar a -> (a -> Eff es (a, b)) -> Eff es b
modifyMVarMasked var f = unsafeUnliftIO $ \unlift -> do modifyMVarMasked var f = reallyUnsafeUnliftIO $ \unlift -> do
M.modifyMVarMasked var $ unlift . f M.modifyMVarMasked var $ unlift . f
-- | Lifted 'M.mkWeakMVar'. -- | Lifted 'M.mkWeakMVar'.
mkWeakMVar :: Concurrent :> es => MVar a -> Eff es () -> Eff es (Weak (MVar a)) mkWeakMVar :: Concurrent :> es => MVar a -> Eff es () -> Eff es (Weak (MVar a))
mkWeakMVar var f = unsafeUnliftIO $ \unlift -> do mkWeakMVar var f = unsafeEff $ \es -> do
M.mkWeakMVar var $ unlift f -- The finalizer can run at any point and in any thread.
M.mkWeakMVar var . unEff f =<< cloneEnv es

View File

@ -97,53 +97,56 @@ import GHC.Natural (Natural)
import Effectful import Effectful
import Effectful.Concurrent.Effect import Effectful.Concurrent.Effect
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
-- | Lifted version of 'STM.atomically' -- | Lifted version of 'STM.atomically'.
atomically :: Concurrent :> es => STM a -> Eff es a atomically :: Concurrent :> es => STM a -> Eff es a
atomically = unsafeEff_ . STM.atomically atomically = unsafeEff_ . STM.atomically
-- | Lifted version of 'STM.newTVarIO' -- | Lifted version of 'STM.newTVarIO'.
newTVarIO :: Concurrent :> es => a -> Eff es (TVar a) newTVarIO :: Concurrent :> es => a -> Eff es (TVar a)
newTVarIO = unsafeEff_ . STM.newTVarIO newTVarIO = unsafeEff_ . STM.newTVarIO
-- | Lifted version of 'STM.readTVarIO' -- | Lifted version of 'STM.readTVarIO'.
readTVarIO :: Concurrent :> es => TVar a -> Eff es a readTVarIO :: Concurrent :> es => TVar a -> Eff es a
readTVarIO = unsafeEff_ . STM.readTVarIO readTVarIO = unsafeEff_ . STM.readTVarIO
-- | Lifted version of 'STM.registerDelay' -- | Lifted version of 'STM.registerDelay'.
registerDelay :: Concurrent :> es => Int -> Eff es (TVar Bool) registerDelay :: Concurrent :> es => Int -> Eff es (TVar Bool)
registerDelay = unsafeEff_ . STM.registerDelay registerDelay = unsafeEff_ . STM.registerDelay
-- | Lifted version of 'STM.mkWeakTVar' -- | Lifted version of 'STM.mkWeakTVar'.
mkWeakTVar :: Concurrent :> es => TVar a -> Eff es () -> Eff es (Weak (TVar a)) mkWeakTVar :: Concurrent :> es => TVar a -> Eff es () -> Eff es (Weak (TVar a))
mkWeakTVar var final = unsafeUnliftIO $ \unlift -> do mkWeakTVar var f = unsafeEff $ \es -> do
STM.mkWeakTVar var $ unlift final -- The finalizer can run at any point and in any thread.
STM.mkWeakTVar var . unEff f =<< cloneEnv es
-- | Lifted version of 'STM.newTMVarIO' -- | Lifted version of 'STM.newTMVarIO'.
newTMVarIO :: Concurrent :> es => a -> Eff es (TMVar a) newTMVarIO :: Concurrent :> es => a -> Eff es (TMVar a)
newTMVarIO = unsafeEff_ . STM.newTMVarIO newTMVarIO = unsafeEff_ . STM.newTMVarIO
-- | Lifted version of 'STM.newEmptyTMVarIO' -- | Lifted version of 'STM.newEmptyTMVarIO'.
newEmptyTMVarIO :: Concurrent :> es => Eff es (TMVar a) newEmptyTMVarIO :: Concurrent :> es => Eff es (TMVar a)
newEmptyTMVarIO = unsafeEff_ STM.newEmptyTMVarIO newEmptyTMVarIO = unsafeEff_ STM.newEmptyTMVarIO
-- | Lifted version of 'STM.mkWeakTMVar' -- | Lifted version of 'STM.mkWeakTMVar'.
mkWeakTMVar :: Concurrent :> es => TMVar a -> Eff es () -> Eff es (Weak (TMVar a)) mkWeakTMVar :: Concurrent :> es => TMVar a -> Eff es () -> Eff es (Weak (TMVar a))
mkWeakTMVar var final = unsafeUnliftIO $ \unlift -> do mkWeakTMVar var f = unsafeEff $ \es -> do
STM.mkWeakTMVar var $ unlift final -- The finalizer can run at any point and in any thread.
STM.mkWeakTMVar var . unEff f =<< cloneEnv es
-- | Lifted version of 'STM.newTChanIO' -- | Lifted version of 'STM.newTChanIO'.
newTChanIO :: Concurrent :> es => Eff es (TChan a) newTChanIO :: Concurrent :> es => Eff es (TChan a)
newTChanIO = unsafeEff_ STM.newTChanIO newTChanIO = unsafeEff_ STM.newTChanIO
-- | Lifted version of 'STM.newBroadcastTChanIO' -- | Lifted version of 'STM.newBroadcastTChanIO'.
newBroadcastTChanIO :: Concurrent :> es => Eff es (TChan a) newBroadcastTChanIO :: Concurrent :> es => Eff es (TChan a)
newBroadcastTChanIO = unsafeEff_ STM.newBroadcastTChanIO newBroadcastTChanIO = unsafeEff_ STM.newBroadcastTChanIO
-- | Lifted version of 'STM.newTQueueIO' -- | Lifted version of 'STM.newTQueueIO'.
newTQueueIO :: Concurrent :> es => Eff es (TQueue a) newTQueueIO :: Concurrent :> es => Eff es (TQueue a)
newTQueueIO = unsafeEff_ STM.newTQueueIO newTQueueIO = unsafeEff_ STM.newTQueueIO
-- | Lifted version of 'STM.newTBQueueIO' -- | Lifted version of 'STM.newTBQueueIO'.
newTBQueueIO :: Concurrent :> es => Natural -> Eff es (TBQueue a) newTBQueueIO :: Concurrent :> es => Natural -> Eff es (TBQueue a)
newTBQueueIO = unsafeEff_ . STM.newTBQueueIO newTBQueueIO = unsafeEff_ . STM.newTBQueueIO

View File

@ -272,7 +272,7 @@ findFileWith
-> [FilePath] -> [FilePath]
-> String -> String
-> Eff es (Maybe FilePath) -> Eff es (Maybe FilePath)
findFileWith p dirs n = unsafeUnliftIO $ \unlift -> do findFileWith p dirs n = unsafeSeqUnliftIO $ \unlift -> do
D.findFileWith (unlift . p) dirs n D.findFileWith (unlift . p) dirs n
-- | Lifted 'D.findFilesWith'. -- | Lifted 'D.findFilesWith'.
@ -282,7 +282,7 @@ findFilesWith
-> [FilePath] -> [FilePath]
-> String -> String
-> Eff es [FilePath] -> Eff es [FilePath]
findFilesWith p dirs ns = unsafeUnliftIO $ \unlift -> do findFilesWith p dirs ns = unsafeSeqUnliftIO $ \unlift -> do
D.findFilesWith (unlift . p) dirs ns D.findFilesWith (unlift . p) dirs ns
---------------------------------------- ----------------------------------------

View File

@ -52,7 +52,7 @@ withFile
-> IOMode -> IOMode
-> (Handle -> Eff es a) -> (Handle -> Eff es a)
-> Eff es a -> Eff es a
withFile fp mode inner = unsafeUnliftIO $ \unlift -> do withFile fp mode inner = unsafeSeqUnliftIO $ \unlift -> do
IO.withFile fp mode $ unlift . inner IO.withFile fp mode $ unlift . inner
-- | Lifted version of 'IO.withBinaryFile'. -- | Lifted version of 'IO.withBinaryFile'.
@ -62,7 +62,7 @@ withBinaryFile
-> IOMode -> IOMode
-> (Handle -> Eff es a) -> (Handle -> Eff es a)
-> Eff es a -> Eff es a
withBinaryFile fp mode inner = unsafeUnliftIO $ \unlift -> do withBinaryFile fp mode inner = unsafeSeqUnliftIO $ \unlift -> do
IO.withBinaryFile fp mode $ unlift . inner IO.withBinaryFile fp mode $ unlift . inner
-- | Lifted version of 'IO.openFile' -- | Lifted version of 'IO.openFile'

View File

@ -133,7 +133,7 @@ withCreateProcess
=> P.CreateProcess => P.CreateProcess
-> (Maybe Handle -> Maybe Handle -> Maybe Handle -> P.ProcessHandle -> Eff es a) -> (Maybe Handle -> Maybe Handle -> Maybe Handle -> P.ProcessHandle -> Eff es a)
-> Eff es a -> Eff es a
withCreateProcess cp cb = unsafeUnliftIO $ \unlift -> do withCreateProcess cp cb = unsafeSeqUnliftIO $ \unlift -> do
P.withCreateProcess cp $ \inh outh errh ph -> unlift $ cb inh outh errh ph P.withCreateProcess cp $ \inh outh errh ph -> unlift $ cb inh outh errh ph
-- | Lifted 'P.cleanupProcess'. -- | Lifted 'P.cleanupProcess'.

View File

@ -29,6 +29,7 @@ import qualified Control.Monad.Trans.Resource.Internal as RI
import Effectful import Effectful
import Effectful.Dispatch.Static import Effectful.Dispatch.Static
import Effectful.Dispatch.Static.Primitive
-- | Data tag for a resource effect. -- | Data tag for a resource effect.
data Resource :: Effect data Resource :: Effect

View File

@ -36,7 +36,7 @@ withSystemTempFile
-> (FilePath -> Handle -> Eff es a) -> (FilePath -> Handle -> Eff es a)
-- ^ Callback that can use the file. -- ^ Callback that can use the file.
-> Eff es a -> Eff es a
withSystemTempFile template action = unsafeUnliftIO $ \unlift -> do withSystemTempFile template action = unsafeSeqUnliftIO $ \unlift -> do
T.withSystemTempFile template $ \fp handle -> unlift $ action fp handle T.withSystemTempFile template $ \fp handle -> unlift $ action fp handle
-- | Lifted 'T.withSystemTempDirectory'. -- | Lifted 'T.withSystemTempDirectory'.
@ -47,7 +47,7 @@ withSystemTempDirectory
-> (FilePath -> Eff es a) -> (FilePath -> Eff es a)
-- ^ Callback that can use the directory. -- ^ Callback that can use the directory.
-> Eff es a -> Eff es a
withSystemTempDirectory template action = unsafeUnliftIO $ \unlift -> do withSystemTempDirectory template action = unsafeSeqUnliftIO $ \unlift -> do
T.withSystemTempDirectory template $ \fp -> unlift $ action fp T.withSystemTempDirectory template $ \fp -> unlift $ action fp
-- | Lifted 'T.withTempFile'. -- | Lifted 'T.withTempFile'.
@ -60,7 +60,7 @@ withTempFile
-> (FilePath -> Handle -> Eff es a) -> (FilePath -> Handle -> Eff es a)
-- ^ Callback that can use the file. -- ^ Callback that can use the file.
-> Eff es a -> Eff es a
withTempFile tmpDir template action = unsafeUnliftIO $ \unlift -> do withTempFile tmpDir template action = unsafeSeqUnliftIO $ \unlift -> do
T.withTempFile tmpDir template $ \fp handle -> unlift $ action fp handle T.withTempFile tmpDir template $ \fp handle -> unlift $ action fp handle
-- | Lifted 'T.withTempDirectory'. -- | Lifted 'T.withTempDirectory'.
@ -73,5 +73,5 @@ withTempDirectory
-> (FilePath -> Eff es a) -> (FilePath -> Eff es a)
-- ^ Callback that can use the directory. -- ^ Callback that can use the directory.
-> Eff es a -> Eff es a
withTempDirectory tmpDir template action = unsafeUnliftIO $ \unlift -> do withTempDirectory tmpDir template action = unsafeSeqUnliftIO $ \unlift -> do
T.withTempDirectory tmpDir template $ \fp -> unlift $ action fp T.withTempDirectory tmpDir template $ \fp -> unlift $ action fp