{-# LANGUAGE CPP #-}
module TH.FixQ (fixQ) where
#if MIN_VERSION_template_haskell(2,17,0)
import Control.Monad.Fix (mfix)
import Language.Haskell.TH.Syntax (Q (..))
fixQ :: (a -> Q a) -> Q a
fixQ :: forall a. (a -> Q a) -> Q a
fixQ = forall (m :: * -> *) a. MonadFix m => (a -> m a) -> m a
mfix
#else
import Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar)
import Control.Exception (BlockedIndefinitelyOnMVar (..), catch, throwIO)
import Control.Exception.Base (FixIOException (..))
import Language.Haskell.TH.Syntax (Q (..), runIO)
import GHC.IO.Unsafe (unsafeDupableInterleaveIO)
fixQ :: (a -> Q a) -> Q a
fixQ k = do
m <- runIO newEmptyMVar
ans <- runIO (unsafeDupableInterleaveIO
(readMVar m `catch` \BlockedIndefinitelyOnMVar ->
throwIO FixIOException))
result <- k ans
runIO (putMVar m result)
return result
#endif