{-# LANGUAGE CPP #-}
{-# OPTIONS_HADDOCK not-home #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Cleff.Internal.Base where
import Cleff.Internal.Effect
import Cleff.Internal.Interpret
import Cleff.Internal.Monad
import Control.Monad.Base (MonadBase (liftBase))
import Control.Monad.Catch (ExitCase (ExitCaseException, ExitCaseSuccess), MonadCatch (catch),
MonadMask (generalBracket, mask, uninterruptibleMask),
MonadThrow (throwM))
import Control.Monad.Primitive (PrimMonad (PrimState, primitive), RealWorld)
import Control.Monad.Trans.Control (MonadBaseControl (StM, liftBaseWith, restoreM))
import qualified Data.Mem as Mem
import GHC.IO (IO (IO))
import System.IO.Unsafe (unsafeDupablePerformIO)
import UnliftIO (MonadIO (liftIO), MonadUnliftIO (withRunInIO), catch, mask, throwIO,
uninterruptibleMask)
data IOE :: Effect where
#ifdef DYNAMIC_IOE
Lift :: IO a -> IOE m a
Unlift :: ((m ~> IO) -> IO a) -> IOE m a
#endif
primLiftIO :: IO a -> Eff es a
primLiftIO :: IO a -> Eff es a
primLiftIO = (Env es -> IO a) -> Eff es a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
(Env es -> IO a) -> Eff es a
Eff ((Env es -> IO a) -> Eff es a)
-> (IO a -> Env es -> IO a) -> IO a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> Env es -> IO a
forall a b. a -> b -> a
const
{-# INLINE primLiftIO #-}
primUnliftIO :: ((Eff es ~> IO) -> IO a) -> Eff es a
primUnliftIO :: ((Eff es ~> IO) -> IO a) -> Eff es a
primUnliftIO (Eff es ~> IO) -> IO a
f = (Env es -> IO a) -> Eff es a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
(Env es -> IO a) -> Eff es a
Eff \Env es
es -> (Eff es ~> IO) -> IO a
f (Eff es a -> Env es -> IO a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
Eff es a -> Env es -> IO a
`unEff` Env es
es)
{-# INLINE primUnliftIO #-}
instance IOE :> es => MonadIO (Eff es) where
#ifdef DYNAMIC_IOE
liftIO = send . Lift
#else
liftIO :: IO a -> Eff es a
liftIO = IO a -> Eff es a
forall a (es :: [(Type -> Type) -> Type -> Type]). IO a -> Eff es a
primLiftIO
{-# INLINE liftIO #-}
#endif
instance IOE :> es => MonadUnliftIO (Eff es) where
#ifdef DYNAMIC_IOE
withRunInIO f = send $ Unlift f
#else
withRunInIO :: ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b
withRunInIO = ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b
forall (es :: [(Type -> Type) -> Type -> Type]) a.
((Eff es ~> IO) -> IO a) -> Eff es a
primUnliftIO
{-# INLINE withRunInIO #-}
#endif
instance IOE :> es => MonadThrow (Eff es) where
throwM :: e -> Eff es a
throwM = e -> Eff es a
forall (m :: Type -> Type) e a.
(MonadIO m, Exception e) =>
e -> m a
throwIO
instance IOE :> es => MonadCatch (Eff es) where
catch :: Eff es a -> (e -> Eff es a) -> Eff es a
catch = Eff es a -> (e -> Eff es a) -> Eff es a
forall (m :: Type -> Type) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
UnliftIO.catch
instance IOE :> es => MonadMask (Eff es) where
mask :: ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b
mask = ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> m a) -> m b) -> m b
UnliftIO.mask
uninterruptibleMask :: ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b
uninterruptibleMask = ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> m a) -> m b) -> m b
UnliftIO.uninterruptibleMask
generalBracket :: Eff es a
-> (a -> ExitCase b -> Eff es c)
-> (a -> Eff es b)
-> Eff es (b, c)
generalBracket Eff es a
ma a -> ExitCase b -> Eff es c
mz a -> Eff es b
m = ((forall a. Eff es a -> Eff es a) -> Eff es (b, c))
-> Eff es (b, c)
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> m a) -> m b) -> m b
UnliftIO.mask \forall a. Eff es a -> Eff es a
restore -> do
a
a <- Eff es a
ma
b
x <- Eff es b -> Eff es b
forall a. Eff es a -> Eff es a
restore (a -> Eff es b
m a
a) Eff es b -> (SomeException -> Eff es b) -> Eff es b
forall (m :: Type -> Type) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
`UnliftIO.catch` \SomeException
e -> do
c
_ <- a -> ExitCase b -> Eff es c
mz a
a (SomeException -> ExitCase b
forall a. SomeException -> ExitCase a
ExitCaseException SomeException
e)
SomeException -> Eff es b
forall (m :: Type -> Type) e a.
(MonadIO m, Exception e) =>
e -> m a
throwIO SomeException
e
c
z <- a -> ExitCase b -> Eff es c
mz a
a (b -> ExitCase b
forall a. a -> ExitCase a
ExitCaseSuccess b
x)
(b, c) -> Eff es (b, c)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (b
x, c
z)
instance IOE :> es => MonadBase IO (Eff es) where
liftBase :: IO α -> Eff es α
liftBase = IO α -> Eff es α
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO
instance IOE :> es => MonadBaseControl IO (Eff es) where
type StM (Eff es) a = a
liftBaseWith :: (RunInBase (Eff es) IO -> IO a) -> Eff es a
liftBaseWith = (RunInBase (Eff es) IO -> IO a) -> Eff es a
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO
restoreM :: StM (Eff es) a -> Eff es a
restoreM = StM (Eff es) a -> Eff es a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
instance IOE :> es => PrimMonad (Eff es) where
type PrimState (Eff es) = RealWorld
primitive :: (State# (PrimState (Eff es))
-> (# State# (PrimState (Eff es)), a #))
-> Eff es a
primitive = IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a)
-> ((State# RealWorld -> (# State# RealWorld, a #)) -> IO a)
-> (State# RealWorld -> (# State# RealWorld, a #))
-> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO
thisIsPureTrustMe :: Eff (IOE ': es) ~> Eff es
thisIsPureTrustMe :: Eff (IOE : es) a -> Eff es a
thisIsPureTrustMe = Handler IOE es -> Eff (IOE : es) ~> Eff es
forall (e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handler e es -> Eff (e : es) ~> Eff es
interpret IOE (Eff esSend) a -> Eff es a
Handler IOE es
\case
#ifdef DYNAMIC_IOE
Lift m -> primLiftIO m
Unlift f -> primUnliftIO \runInIO -> f (runInIO . toEff)
#endif
{-# INLINE thisIsPureTrustMe #-}
runEff :: Eff '[] a -> IO a
runEff :: Eff '[] a -> IO a
runEff Eff '[] a
m = Eff '[] a -> Env '[] -> IO a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
Eff es a -> Env es -> IO a
unEff Eff '[] a
m Env '[]
forall k (f :: k -> Type). Mem f '[]
Mem.empty
{-# INLINE runEff #-}
runIOE :: Eff '[IOE] ~> IO
runIOE :: Eff '[IOE] a -> IO a
runIOE = Eff '[] a -> IO a
forall a. Eff '[] a -> IO a
runEff (Eff '[] a -> IO a)
-> (Eff '[IOE] a -> Eff '[] a) -> Eff '[IOE] a -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff '[IOE] a -> Eff '[] a
forall (es :: [(Type -> Type) -> Type -> Type]).
Eff (IOE : es) ~> Eff es
thisIsPureTrustMe
{-# INLINE runIOE #-}
runPure :: Eff '[] a -> a
runPure :: Eff '[] a -> a
runPure = IO a -> a
forall a. IO a -> a
unsafeDupablePerformIO (IO a -> a) -> (Eff '[] a -> IO a) -> Eff '[] a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff '[] a -> IO a
forall a. Eff '[] a -> IO a
runEff
{-# NOINLINE runPure #-}
type HandlerIO e es = ∀ esSend. (Handling e es esSend) => e (Eff esSend) ~> IO
interpretIO :: IOE :> es => HandlerIO e es -> Eff (e ': es) ~> Eff es
interpretIO :: HandlerIO e es -> Eff (e : es) ~> Eff es
interpretIO HandlerIO e es
f = Handler e es -> Eff (e : es) ~> Eff es
forall (e :: (Type -> Type) -> Type -> Type)
(es :: [(Type -> Type) -> Type -> Type]).
Handler e es -> Eff (e : es) ~> Eff es
interpret (IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a)
-> (e (Eff esSend) a -> IO a) -> e (Eff esSend) a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e (Eff esSend) a -> IO a
HandlerIO e es
f)
{-# INLINE interpretIO #-}
withToIO :: (Handling e es esSend, IOE :> es) => ((Eff esSend ~> IO) -> IO a) -> Eff es a
withToIO :: ((Eff esSend ~> IO) -> IO a) -> Eff es a
withToIO (Eff esSend ~> IO) -> IO a
f = (Env es -> IO a) -> Eff es a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
(Env es -> IO a) -> Eff es a
Eff \Env es
es -> (Eff esSend ~> IO) -> IO a
f \Eff esSend a
m -> Eff esSend a -> Env esSend -> IO a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
Eff es a -> Env es -> IO a
unEff Eff esSend a
m (Env es -> Env esSend -> Env esSend
forall k (es :: [k]) (es' :: [k]) (f :: k -> Type).
Mem f es' -> Mem f es -> Mem f es
Mem.update Env es
es Env esSend
forall k (e :: (Type -> Type) -> Type -> Type) (es :: k)
(esSend :: [(Type -> Type) -> Type -> Type]).
Handling e es esSend =>
Env esSend
sendEnv)
fromIO :: (Handling e es esSend, IOE :> es) => IO ~> Eff esSend
fromIO :: IO ~> Eff esSend
fromIO = (Env esSend -> IO a) -> Eff esSend a
forall (es :: [(Type -> Type) -> Type -> Type]) a.
(Env es -> IO a) -> Eff es a
Eff ((Env esSend -> IO a) -> Eff esSend a)
-> (IO a -> Env esSend -> IO a) -> IO a -> Eff esSend a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> Env esSend -> IO a
forall a b. a -> b -> a
const