{-# LANGUAGE CPP #-}
{-# OPTIONS_HADDOCK not-home #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Cleff.Internal.Base
(
IOE
, primLiftIO
, primUnliftIO
, MonadIO (liftIO)
, MonadUnliftIO (withRunInIO)
, thisIsPureTrustMe
, runIOE
, runPure
, runPureIO
, HandlerIO
, interpretIO
, withToIO
, fromIO
) where
import qualified Cleff.Internal.Env as Env
import Cleff.Internal.Interpret
import Cleff.Internal.Monad
import qualified Cleff.Internal.Stack as Stack
import Control.Monad.Base (MonadBase (liftBase))
import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
import qualified Control.Monad.Catch as Catch
import Control.Monad.IO.Unlift (MonadIO (liftIO), MonadUnliftIO (withRunInIO))
import Control.Monad.Primitive (PrimMonad (PrimState, primitive), RealWorld)
import Control.Monad.Trans.Control (MonadBaseControl (StM, liftBaseWith, restoreM))
import GHC.IO (IO (IO))
import System.IO.Unsafe (unsafeDupablePerformIO)
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 :: [Effect]) 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
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 :: [Effect]) a. (Env es -> IO a) -> Eff es a
Eff \Env es
es -> (Eff es ~> IO) -> IO a
f \(Eff Env es -> IO a
m) -> Env es -> IO a
m Env es
es
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 :: [Effect]). IO a -> Eff es a
primLiftIO
#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 :: [Effect]) a. ((Eff es ~> IO) -> IO a) -> Eff es a
primUnliftIO
#endif
instance IOE :> es => MonadThrow (Eff es) where
throwM :: e -> Eff es a
throwM = IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a) -> (e -> IO a) -> e -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> IO a
forall (m :: Type -> Type) e a.
(MonadThrow m, Exception e) =>
e -> m a
Catch.throwM
instance IOE :> es => MonadCatch (Eff es) where
catch :: Eff es a -> (e -> Eff es a) -> Eff es a
catch Eff es a
m e -> Eff es a
h = ((forall a. Eff es a -> IO a) -> IO a) -> Eff es a
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO \forall a. Eff es a -> IO a
run -> IO a -> (e -> IO a) -> IO a
forall (m :: Type -> Type) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
Catch.catch (Eff es a -> IO a
forall a. Eff es a -> IO a
run Eff es a
m) (Eff es a -> IO a
forall a. Eff es a -> IO a
run (Eff es a -> IO a) -> (e -> Eff es a) -> e -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Eff es a
h)
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
f = ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO \forall a. Eff es a -> IO a
run -> ((forall a. IO a -> IO a) -> IO b) -> IO b
forall (m :: Type -> Type) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
Catch.mask \forall a. IO a -> IO a
restore -> Eff es b -> IO b
forall a. Eff es a -> IO a
run (Eff es b -> IO b) -> Eff es b -> IO b
forall a b. (a -> b) -> a -> b
$ (forall a. Eff es a -> Eff es a) -> Eff es b
f (IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a) -> (Eff es a -> IO a) -> Eff es a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> IO a
forall a. IO a -> IO a
restore (IO a -> IO a) -> (Eff es a -> IO a) -> Eff es a -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es a -> IO a
forall a. Eff es a -> IO a
run)
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
f = ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO \forall a. Eff es a -> IO a
run -> ((forall a. IO a -> IO a) -> IO b) -> IO b
forall (m :: Type -> Type) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
Catch.uninterruptibleMask \forall a. IO a -> IO a
restore -> Eff es b -> IO b
forall a. Eff es a -> IO a
run (Eff es b -> IO b) -> Eff es b -> IO b
forall a b. (a -> b) -> a -> b
$ (forall a. Eff es a -> Eff es a) -> Eff es b
f (IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a) -> (Eff es a -> IO a) -> Eff es a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> IO a
forall a. IO a -> IO a
restore (IO a -> IO a) -> (Eff es a -> IO a) -> Eff es a -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es a -> IO a
forall a. Eff es a -> IO a
run)
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 -> IO a) -> IO (b, c)) -> Eff es (b, c)
forall (m :: Type -> Type) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO \forall a. Eff es a -> IO a
run -> IO a -> (a -> ExitCase b -> IO c) -> (a -> IO b) -> IO (b, c)
forall (m :: Type -> Type) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
Catch.generalBracket (Eff es a -> IO a
forall a. Eff es a -> IO a
run Eff es a
ma) (\a
x ExitCase b
e -> Eff es c -> IO c
forall a. Eff es a -> IO a
run (Eff es c -> IO c) -> Eff es c -> IO c
forall a b. (a -> b) -> a -> b
$ a -> ExitCase b -> Eff es c
mz a
x ExitCase b
e) (Eff es b -> IO b
forall a. Eff es a -> IO a
run (Eff es b -> IO b) -> (a -> Eff es b) -> a -> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Eff es b
m)
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 =
#ifndef DYNAMIC_IOE
(Stack es -> Stack (IOE : es)) -> Eff (IOE : es) ~> Eff es
forall (es :: [Effect]) (es' :: [Effect]).
(Stack es' -> Stack es) -> Eff es ~> Eff es'
adjust (HandlerPtr IOE -> Stack es -> Stack (IOE : es)
forall (e :: Effect) (es :: [Effect]).
HandlerPtr e -> Stack es -> Stack (e : es)
Stack.cons (HandlerPtr IOE -> Stack es -> Stack (IOE : es))
-> HandlerPtr IOE -> Stack es -> Stack (IOE : es)
forall a b. (a -> b) -> a -> b
$ Int -> HandlerPtr IOE
forall (e :: Effect). Int -> HandlerPtr e
HandlerPtr (-Int
1))
#else
interpret \case
Lift m -> primLiftIO m
Unlift f -> primUnliftIO \runInIO -> f (runInIO . toEff)
#endif
{-# INLINE thisIsPureTrustMe #-}
runIOE :: Eff '[IOE] ~> IO
runIOE :: Eff '[IOE] a -> IO a
runIOE = Eff '[] a -> IO a
Eff '[] ~> IO
runPureIO (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 :: [Effect]). 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
Eff '[] ~> IO
runPureIO
{-# INLINE runPure #-}
runPureIO :: Eff '[] ~> IO
runPureIO :: Eff '[] a -> IO a
runPureIO = \(Eff Env '[] -> IO a
m) -> Env '[] -> IO a
m Env '[]
Env.empty
{-# INLINE runPureIO #-}
type HandlerIO e es = ∀ esSend. Handling esSend e es => 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 :: Effect) (es :: [Effect]).
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 esSend e es, 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 :: [Effect]) a. (Env es -> IO a) -> Eff es a
Eff \Env es
es -> (Eff esSend ~> IO) -> IO a
f \(Eff Env esSend -> IO a
m) -> Env esSend -> IO a
m (Env es -> Env esSend -> Env esSend
forall (es :: [Effect]) (es' :: [Effect]).
Env es' -> Env es -> Env es
Env.update Env es
es Env esSend
forall k (esSend :: [Effect]) (e :: Effect) (es :: k).
Handling esSend e es =>
Env esSend
esSend)
{-# INLINE withToIO #-}
fromIO :: (Handling esSend e es, IOE :> es) => IO ~> Eff esSend
fromIO :: IO ~> Eff esSend
fromIO = (Env esSend -> IO a) -> Eff esSend a
forall (es :: [Effect]) 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
{-# INLINE fromIO #-}