quotet-0.0.0.0: src/Control/Monad/Quote/Internal.hs
{-# LANGUAGE CPP #-}
-- | Internal module, no stability guarantees
module Control.Monad.Quote.Internal
( Quote (..),
QuoteT (..),
runQuoteT,
)
where
import Control.Applicative
import Control.Monad.Cont.Class
import Control.Monad.Error.Class
import Control.Monad.RWS.Class
import Control.Monad.State.Strict
import Language.Haskell.TH.Syntax (Uniq, mkNameU)
import Language.Haskell.TH.Syntax.Compat (Quote (..))
#ifdef MIN_VERSION_exceptions
import Control.Monad.Catch
#endif
#ifdef MIN_VERSION_semigroupoids
import Data.Functor.Apply (Apply (..))
import Data.Functor.Bind (Bind (..))
#endif
#ifdef MIN_VERSION_monad_control
import Control.Monad.Base
import Control.Monad.Trans.Control
#endif
-- $setup
-- >>> import Language.Haskell.TH (Exp)
-- >>> import Control.Monad.Reader
-- | The 'QuoteT' monad transformer. Also see 'runQuoteT'.
--
-- Useful to add a 'Quote' instance to any monad transformer stack.
--
-- Internally, this is a newtype of @'StateT' 'Uniq'@.
newtype QuoteT m a = QuoteT {unQuoteT :: StateT Uniq m a}
deriving newtype
( Functor,
Applicative,
Monad,
MonadFail,
MonadIO,
Alternative,
MonadPlus,
MonadFix,
MonadTrans,
MonadReader r,
MonadWriter w,
MonadRWS r w s,
MonadCont,
MonadError e
)
#ifdef MIN_VERSION_exceptions
deriving newtype (MonadThrow, MonadCatch, MonadMask)
#endif
#ifdef MIN_VERSION_semigroupoids
deriving newtype (Apply)
#endif
#ifdef MIN_VERSION_monad_control
deriving newtype (MonadBase b, MonadBaseControl b, MonadTransControl)
#endif
instance MonadState s m => MonadState s (QuoteT m) where
get = lift get
put = lift . put
state = lift . state
instance Monad m => Quote (QuoteT m) where
newName s = QuoteT . state $ \i -> (mkNameU s i, i + 1)
#ifdef MIN_VERSION_semigroupoids
instance Bind m => Bind (QuoteT m) where
QuoteT sma >>- f = QuoteT $ sma >>- unQuoteT . f
#endif
-- | Extract @m a@ from @'QuoteT' m a@, where @'QuoteT' m@ is always an instance of 'Quote'.
--
-- On GHC 9.0+, you can use this to extract an 'Language.Haskell.TH.Exp' out of a quotation bracket:
--
-- >>> import qualified Language.Haskell.TH.Lib as TH
-- >>> :{
-- let mExp :: (Quote m, MonadReader String m) => m Exp
-- mExp = [| \a -> a <> $(TH.stringE =<< ask) |]
-- exp :: Exp
-- exp = flip runReader " world" . runQuoteT $ mExp
-- in exp
-- :}
-- LamE [VarP a_0] (InfixE (Just (VarE a_0)) (VarE GHC.Base.<>) (Just (LitE (StringL " world"))))
runQuoteT :: Monad m => QuoteT m a -> m a
runQuoteT = flip evalStateT 0 . unQuoteT