module Control.Monad.Primitive (
PrimMonad(..), RealWorld, primitive_,
PrimBase(..),
liftPrim, primToPrim, primToIO, primToST,
unsafePrimToPrim, unsafePrimToIO, unsafePrimToST,
unsafeInlinePrim, unsafeInlineIO, unsafeInlineST,
touch
) where
import GHC.Prim ( State#, RealWorld, touch# )
import GHC.Base ( unsafeCoerce#, realWorld# )
#if MIN_VERSION_base(4,2,0)
import GHC.IO ( IO(..) )
#else
import GHC.IOBase ( IO(..) )
#endif
import GHC.ST ( ST(..) )
import Control.Monad.Trans.Class (lift)
import Data.Monoid (Monoid)
import Control.Monad.Trans.Identity ( IdentityT)
import Control.Monad.Trans.List ( ListT )
import Control.Monad.Trans.Maybe ( MaybeT )
import Control.Monad.Trans.Error ( ErrorT, Error)
import Control.Monad.Trans.Reader ( ReaderT )
import Control.Monad.Trans.State ( StateT )
import Control.Monad.Trans.Writer ( WriterT )
import Control.Monad.Trans.RWS ( RWST )
#if MIN_VERSION_transformers(0,4,0)
import Control.Monad.Trans.Except ( ExceptT )
#endif
import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST )
import qualified Control.Monad.Trans.State.Strict as Strict ( StateT )
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
class Monad m => PrimMonad m where
type PrimState m
primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
class PrimMonad m => PrimBase m where
internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)
primitive_ :: PrimMonad m
=> (State# (PrimState m) -> State# (PrimState m)) -> m ()
primitive_ f = primitive (\s# ->
case f s# of
s'# -> (# s'#, () #))
instance PrimMonad IO where
type PrimState IO = RealWorld
primitive = IO
instance PrimBase IO where
internal (IO p) = p
instance PrimMonad m => PrimMonad (IdentityT m) where
type PrimState (IdentityT m) = PrimState m
primitive = lift . primitive
instance PrimMonad m => PrimMonad (ListT m) where
type PrimState (ListT m) = PrimState m
primitive = lift . primitive
instance PrimMonad m => PrimMonad (MaybeT m) where
type PrimState (MaybeT m) = PrimState m
primitive = lift . primitive
instance (Error e, PrimMonad m) => PrimMonad (ErrorT e m) where
type PrimState (ErrorT e m) = PrimState m
primitive = lift . primitive
instance PrimMonad m => PrimMonad (ReaderT r m) where
type PrimState (ReaderT r m) = PrimState m
primitive = lift . primitive
instance PrimMonad m => PrimMonad (StateT s m) where
type PrimState (StateT s m) = PrimState m
primitive = lift . primitive
instance (Monoid w, PrimMonad m) => PrimMonad (WriterT w m) where
type PrimState (WriterT w m) = PrimState m
primitive = lift . primitive
instance (Monoid w, PrimMonad m) => PrimMonad (RWST r w s m) where
type PrimState (RWST r w s m) = PrimState m
primitive = lift . primitive
#if MIN_VERSION_transformers(0,4,0)
instance PrimMonad m => PrimMonad (ExceptT e m) where
type PrimState (ExceptT e m) = PrimState m
primitive = lift . primitive
#endif
instance PrimMonad m => PrimMonad (Strict.StateT s m) where
type PrimState (Strict.StateT s m) = PrimState m
primitive = lift . primitive
instance (Monoid w, PrimMonad m) => PrimMonad (Strict.WriterT w m) where
type PrimState (Strict.WriterT w m) = PrimState m
primitive = lift . primitive
instance (Monoid w, PrimMonad m) => PrimMonad (Strict.RWST r w s m) where
type PrimState (Strict.RWST r w s m) = PrimState m
primitive = lift . primitive
instance PrimMonad (ST s) where
type PrimState (ST s) = s
primitive = ST
instance PrimBase (ST s) where
internal (ST p) = p
liftPrim
:: (PrimBase m1, PrimMonad m2, PrimState m1 ~ PrimState m2) => m1 a -> m2 a
liftPrim = primToPrim
primToPrim :: (PrimBase m1, PrimMonad m2, PrimState m1 ~ PrimState m2)
=> m1 a -> m2 a
primToPrim m = primitive (internal m)
primToIO :: (PrimBase m, PrimState m ~ RealWorld) => m a -> IO a
primToIO = primToPrim
primToST :: PrimBase m => m a -> ST (PrimState m) a
primToST = primToPrim
unsafePrimToPrim :: (PrimBase m1, PrimMonad m2) => m1 a -> m2 a
unsafePrimToPrim m = primitive (unsafeCoerce# (internal m))
unsafePrimToST :: PrimBase m => m a -> ST s a
unsafePrimToST = unsafePrimToPrim
unsafePrimToIO :: PrimBase m => m a -> IO a
unsafePrimToIO = unsafePrimToPrim
unsafeInlinePrim :: PrimBase m => m a -> a
unsafeInlinePrim m = unsafeInlineIO (unsafePrimToIO m)
unsafeInlineIO :: IO a -> a
unsafeInlineIO m = case internal m realWorld# of (# _, r #) -> r
unsafeInlineST :: ST s a -> a
unsafeInlineST = unsafeInlinePrim
touch :: PrimMonad m => a -> m ()
touch x = unsafePrimToPrim
$ (primitive (\s -> case touch# x s of { s' -> (# s', () #) }) :: IO ())