io-classes-1.8.0.0: src/Control/Monad/Class/MonadST.hs
module Control.Monad.Class.MonadST (MonadST (..)) where
import Control.Monad.Reader
import Control.Monad.Primitive
import Control.Monad.ST (ST)
-- | This class is for abstracting over 'stToIO' which allows running 'ST'
-- actions in 'IO'. In this case it is to allow running 'ST' actions within
-- another monad @m@.
--
-- The normal type of 'stToIO' is:
--
-- > stToIO :: ST RealWorld a -> IO a
--
-- We have two approaches to abstracting over this, a new and an older
-- (deprecated) method. The new method borrows the @primitive@ package's
-- 'PrimMonad' and 'PrimState' type family. This gives us:
--
-- > stToIO :: ST (PrimState m) a -> m a
--
-- Which for 'IO' is exactly the same as above. For 'ST' it is identity, while
-- for @IOSim@ it is
--
-- > stToIO :: ST s a -> IOSim s a
--
-- The older (deprecated) method is tricky because we need to not care about
-- both the @IO@, and also the @RealWorld@, and it does so avoiding mentioning
-- any @s@ type (which is what the 'PrimState' type family gives access to).
-- The solution is to write an action that is given the @liftST@ as an argument
-- and where that action itself is polymorphic in the @s@ parameter. This
-- allows us to instantiate it with @RealWorld@ in the @IO@ case, and the local
-- @s@ in a case where we are embedding into another @ST@ action.
--
class PrimMonad m => MonadST m where
-- | @since 1.4.1.0
stToIO :: ST (PrimState m) a -> m a
-- | Deprecated. Use 'stToIO' instead.
withLiftST :: (forall s. (forall a. ST s a -> m a) -> b) -> b
withLiftST = \k -> k stToIO
{-# DEPRECATED withLiftST "Use the simpler 'stToIO' instead." #-}
instance MonadST IO where
stToIO = stToPrim
instance MonadST (ST s) where
stToIO = stToPrim
withLiftST = \f -> f id
instance (MonadST m, PrimMonad m) => MonadST (ReaderT r m) where
stToIO :: ST (PrimState m) a -> ReaderT r m a
stToIO f = lift (stToPrim f)
withLiftST f = withLiftST $ \g -> f (lift . g)