{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MonomorphismRestriction #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS -fwarn-missing-signatures #-}
module MonadRQ
where
import Generics.MultiRec.TH.Alt.DerivOptions
import THUtils(AppliedTyCon, toAppliedTyCon, pprintUnqual)
import Control.Monad.Reader(Monad(return, fail, (>>=)),
Functor(..), (=<<), mapM, sequence,
MonadTrans(..), when, zipWithM,
ReaderT(runReaderT), asks)
import Language.Haskell.TH(Q, TypeQ, Type, report, runIO)
import Data.Map(Map, fromListWithKey, toList)
import Control.Applicative((<$>))
askConstructorNameModifier :: RQ (String -> String -> String)
askConstructorNameModifier = asks (constructorNameModifier . derivOptions)
askVerbose :: RQ Bool
askVerbose = asks (verbose . derivOptions)
askSumMode :: RQ SumMode
askSumMode = asks (sumMode . derivOptions)
message :: String -> RQ ()
message x =
do
b <- askVerbose
when b (liftq . runIO . putStrLn $ x ++ "\n")
messageReport :: String -> RQ ()
messageReport x =
do
b <- askVerbose
when b (liftq . report False $ x ++ "\n")
-- checkOptions :: DerivOptions -> Q ()
-- checkOptions (DerivOptions{..}) =
-- do
-- when (null familyTypes) (fail "empty family")
data Env = Env {
derivOptions :: DerivOptions,
familyTypesMap :: Map AppliedTyCon String
}
type RQ = ReaderT Env Q
liftq :: Q a -> RQ a
liftq = lift
foreachType :: ((AppliedTyCon,String) -> RQ a) -> RQ [a]
foreachType f = mapM f . toList =<< asks familyTypesMap
foreachTypeNumbered :: (Int -> Int -> (AppliedTyCon,String) -> RQ a) -> RQ [a]
foreachTypeNumbered f = do
ns <- toList <$> asks familyTypesMap
zipWithM (f (length ns)) [0..] ns
runRQ :: RQ a -> DerivOptions -> Q a
runRQ x opts = do
ft' <- sequence
. fmap (\(x,y) -> x >>= (\x' -> return (x',y)))
. familyTypes $ opts
:: Q [(Type,String)]
when (Prelude.null ft') (fail ("Empty family not supported."))
ft'' <- mapM (\(t,s) -> do
t' <- toAppliedTyCon t
case t' of
Left err -> fail err
Right t'' -> return (t'',s))
ft'
let
ftm = fromListWithKey collision ft''
runReaderT x Env { derivOptions = opts, familyTypesMap = ftm }
where
collision :: AppliedTyCon -> String -> String -> a
collision k a b = error ("collision : "
++ "\n key = "++pprintUnqual k
++ "\n values = "++show(a,b)
)