@@ -58,17 +58,18 @@ module Effectful.Internal.Monad
58import Control.Applicative (liftA2)
58import Control.Applicative (liftA2)
59import Control.Concurrent (myThreadId)
59import Control.Concurrent (myThreadId)
60import Control.Exception
60import Control.Exception
61−import Control.Monad.Base
62import Control.Monad.Fix
61import Control.Monad.Fix
63import Control.Monad.IO.Class
62import Control.Monad.IO.Class
64−import Control.Monad.IO.Unlift
65import Control.Monad.Primitive
63import Control.Monad.Primitive
66−import Control.Monad.Trans.Control
67import Data.Unique
64import Data.Unique
68import GHC.Exts (oneShot)
65import GHC.Exts (oneShot)
69import GHC.IO (IO(..))
66import GHC.IO (IO(..))
67+import GHC.Stack (HasCallStack)
70import System.IO.Unsafe (unsafeDupablePerformIO)
68import System.IO.Unsafe (unsafeDupablePerformIO)
69+import qualified Control.Monad.Base as M
71import qualified Control.Monad.Catch as E
70import qualified Control.Monad.Catch as E
71+import qualified Control.Monad.IO.Unlift as M
72+import qualified Control.Monad.Trans.Control as M
73import Effectful.Internal.Effect
74import Effectful.Internal.Effect
74import Effectful.Internal.Env
75import Effectful.Internal.Env
@@ -143,13 +144,18 @@ unsafeEff_ m = unsafeEff $ \_ -> m
143-- /Note:/ the 'IO' operation must not run its argument in a separate thread,
144-- /Note:/ the 'IO' operation must not run its argument in a separate thread,
144-- attempting to do so will result in a runtime error.
145-- attempting to do so will result in a runtime error.
145unsafeWithLiftMapIO
146unsafeWithLiftMapIO
146− :: ((forall a b localEs. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
148+ => ((forall a b localEs. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
147 -> Eff es r
149 -> Eff es r
148unsafeWithLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
150unsafeWithLiftMapIO k = k $ \mapIO m -> unsafeEff $ \es -> do
149 unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
151 unsafeSeqUnliftEff es $ \unlift -> mapIO $ unlift m
151-- | Lower 'Eff' operations into 'IO' ('SeqUnlift').
153-- | Lower 'Eff' operations into 'IO' ('SeqUnlift').
152−unsafeSeqUnliftEff :: Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
157+ -> ((forall r. Eff es r -> IO r) -> IO a)
153unsafeSeqUnliftEff es k = do
159unsafeSeqUnliftEff es k = do
154 tid0 <- myThreadId
160 tid0 <- myThreadId
155 k $ \m -> do
161 k $ \m -> do
@@ -162,7 +168,8 @@ unsafeSeqUnliftEff es k = do
163-- | Lower 'Eff' operations into 'IO' ('ConcUnlift').
169-- | Lower 'Eff' operations into 'IO' ('ConcUnlift').
164unsafeConcUnliftEff
170unsafeConcUnliftEff
165− :: Env es
172+ => Env es
166 -> Persistence
173 -> Persistence
168 -> ((forall r. Eff es r -> IO r) -> IO a)
175 -> ((forall r. Eff es r -> IO r) -> IO a)
@@ -283,20 +290,40 @@ runEff m = unEff (evalEffect (IdE (IOE SeqUnlift)) m) =<< emptyEnv
283instance IOE :> es => MonadIO (Eff es) where
290instance IOE :> es => MonadIO (Eff es) where
284 liftIO = unsafeEff_
291 liftIO = unsafeEff_
286−instance IOE :> es => MonadUnliftIO (Eff es) where
293+instance IOE :> es => M.MonadUnliftIO (Eff es) where
287− withRunInIO = unliftEff
294+ withRunInIO = withRunInIO
296+ -- A trick to show name of the function in the call stack.
298+ :: (HasCallStack, IOE :> es)
299+ => ((forall r. Eff es r -> IO r) -> IO a)
301+ withRunInIO f = unliftStrategy >>= \case
302+ SeqUnlift -> unsafeEff $ \es -> unsafeSeqUnliftEff es f
303+ ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
304+ unsafeEff $ \es -> unsafeConcUnliftEff es p b f
289-- | Instance included for compatibility with existing code, usage of 'liftIO'
306-- | Instance included for compatibility with existing code, usage of 'liftIO'
290-- is preferrable.
307-- is preferrable.
291−instance IOE :> es => MonadBase IO (Eff es) where
308+instance IOE :> es => M.MonadBase IO (Eff es) where
292 liftBase = unsafeEff_
309 liftBase = unsafeEff_
294-- | Instance included for compatibility with existing code, usage of
311-- | Instance included for compatibility with existing code, usage of
295-- 'withRunInIO' is preferrable.
312-- 'withRunInIO' is preferrable.
296−instance IOE :> es => MonadBaseControl IO (Eff es) where
313+instance IOE :> es => M.MonadBaseControl IO (Eff es) where
297 type StM (Eff es) a = a
314 type StM (Eff es) a = a
298− liftBaseWith = unliftEff
299 restoreM = pure
315 restoreM = pure
316+ liftBaseWith = liftBaseWith
318+ -- A trick to show name of the function in the call stack.
320+ :: (HasCallStack, IOE :> es)
321+ => ((forall r. Eff es r -> IO r) -> IO a)
323+ liftBaseWith f = unliftStrategy >>= \case
324+ SeqUnlift -> unsafeEff $ \es -> unsafeSeqUnliftEff es f
325+ ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
326+ unsafeEff $ \es -> unsafeConcUnliftEff es p b f
301----------------------------------------
328----------------------------------------
302-- Primitive
329-- Primitive
@@ -378,13 +405,6 @@ unliftStrategy = readerEffectM $ \(IdE (IOE unlift)) -> pure unlift
378withUnliftStrategy :: IOE :> es => UnliftStrategy -> Eff es a -> Eff es a
405withUnliftStrategy :: IOE :> es => UnliftStrategy -> Eff es a -> Eff es a
379withUnliftStrategy unlift = localEffect $ \_ -> IdE (IOE unlift)
406withUnliftStrategy unlift = localEffect $ \_ -> IdE (IOE unlift)
381−-- | Helper for 'MonadBaseControl' and 'MonadUnliftIO' instances.
382−unliftEff :: IOE :> es => ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a
383−unliftEff f = unliftStrategy >>= \case
384− SeqUnlift -> unsafeEff $ \es -> unsafeSeqUnliftEff es f
385− ConcUnlift p b -> withUnliftStrategy SeqUnlift $ do
386− unsafeEff $ \es -> unsafeConcUnliftEff es p b f
388----------------------------------------
408----------------------------------------
389-- Helpers
409-- Helpers