    ------------------------------------------------------------------------
    -- |
    -- Module           : What4.Utils.MonadST
    -- Description      : Typeclass for monads generalizing ST
    -- Copyright        : (c) Galois, Inc 2014-2020
    -- License          : BSD3
    -- Maintainer       : Joe Hendrix <jhendrix@galois.com>
    -- Stability        : provisional
    --
    -- This module defines the MonadST class, which contains the ST
    -- and IO monads and a small collection of moand transformers over them.
    ------------------------------------------------------------------------

    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE UndecidableInstances #-}

    module What4.Utils.MonadST
      ( MonadST(..)
      , Control.Monad.ST.ST
      , RealWorld
      ) where

    import Control.Monad.ST
    import Control.Monad.Cont
    import Control.Monad.Reader
    import Control.Monad.State as L
    import Control.Monad.State.Strict as S
    import Control.Monad.Writer as L
    import Control.Monad.Writer.Strict as S

    class Monad m => MonadST s m | m -> s where
      liftST :: ST s a -> m a

    instance MonadST RealWorld IO where
      liftST :: forall a. ST RealWorld a -> IO a
    liftST = ST RealWorld a -> IO a
    forall a. ST RealWorld a -> IO a
    stToIO

    instance MonadST s (ST s) where
      liftST :: forall a. ST s a -> ST s a
    liftST = ST s a -> ST s a
    forall a. a -> a
    id

    instance MonadST s m => MonadST s (ContT r m) where
      liftST :: forall a. ST s a -> ContT r m a
    liftST ST s a
    m = m a -> ContT r m a
    forall (m :: Type -> Type) a. Monad m => m a -> ContT r m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> ContT r m a) -> m a -> ContT r m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m

    instance MonadST s m => MonadST s (ReaderT r m) where
      liftST :: forall a. ST s a -> ReaderT r m a
    liftST ST s a
    m = m a -> ReaderT r m a
    forall (m :: Type -> Type) a. Monad m => m a -> ReaderT r m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> ReaderT r m a) -> m a -> ReaderT r m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m

    instance MonadST s m => MonadST s (L.StateT u m) where
      liftST :: forall a. ST s a -> StateT u m a
    liftST ST s a
    m = m a -> StateT u m a
    forall (m :: Type -> Type) a. Monad m => m a -> StateT u m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> StateT u m a) -> m a -> StateT u m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m

    instance MonadST s m => MonadST s (S.StateT u m) where
      liftST :: forall a. ST s a -> StateT u m a
    liftST ST s a
    m = m a -> StateT u m a
    forall (m :: Type -> Type) a. Monad m => m a -> StateT u m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> StateT u m a) -> m a -> StateT u m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m

    instance (MonadST s m, Monoid w) => MonadST s (L.WriterT w m) where
      liftST :: forall a. ST s a -> WriterT w m a
    liftST ST s a
    m = m a -> WriterT w m a
    forall (m :: Type -> Type) a. Monad m => m a -> WriterT w m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> WriterT w m a) -> m a -> WriterT w m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m

    instance (MonadST s m, Monoid w) => MonadST s (S.WriterT w m) where
      liftST :: forall a. ST s a -> WriterT w m a
    liftST ST s a
    m = m a -> WriterT w m a
    forall (m :: Type -> Type) a. Monad m => m a -> WriterT w m a
    forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (m a -> WriterT w m a) -> m a -> WriterT w m a
    forall a b. (a -> b) -> a -> b
    $ ST s a -> m a
    forall a. ST s a -> m a
    forall s (m :: Type -> Type) a. MonadST s m => ST s a -> m a
    liftST ST s a
    m