module NewtypeDeriving.Rendering where
import BasePrelude
import Control.Monad.Base
import Control.Monad.Trans.Control
import Control.Monad.Trans.Class
import NewtypeDeriving.TH
import Language.Haskell.TH
monadTransInstance
:: Type
-> Name
-> Int
-> Dec
monadTransInstance transformerType conName layersCount =
head $ purifyQ $
[d|
instance MonadTrans $(pure transformerType) where
lift =
$(pure liftExp)
|]
where
liftExp =
foldl' composeExp (ConE conName) $ replicate layersCount (VarE 'lift)
monadBaseTransformerInstance
:: Type
-> Name
-> Dec
monadBaseTransformerInstance transformerType conName =
head $ purifyQ $
[d|
instance MonadBase b m => MonadBase b ($(pure transformerType) m) where
liftBase =
$(conE conName) . liftBase
|]
monadTransControlInstance
:: Type
-> Name
-> [Type]
-> Dec
monadTransControlInstance transformerType conName layers =
head $ purifyQ $
[d|
instance MonadTransControl $(pure transformerType) where
type StT $(pure transformerType) $(varT stArgName) =
$(pure stType)
liftWith =
$(pure liftWithExp)
restoreT =
$(pure restoreTExp)
|]
where
restoreTExp =
foldl' composeExp (ConE conName) $
replicate (length layers) (VarE 'restoreT)
liftWithExp =
LamE [VarP onUnliftVarName] $
AppE (ConE conName) $
foldr' (\n -> AppE (VarE 'liftWith) . LamE [VarP n])
(AppE (VarE onUnliftVarName) unliftExp)
(unliftNames)
where
onUnliftVarName =
mkName "onUnlift"
unliftNames =
zipWith (\_ i -> mkName $ "unlift" <> show i) layers [1..]
unliftExp =
foldr' composeExp unwrapExp $ map VarE $ reverse unliftNames
unwrapExp =
LamE [ConP conName [VarP mVarName]] (VarE mVarName)
where
mVarName =
mkName "m"
stArgName =
mkName "a"
stType =
foldl' (flip AppT) (VarT stArgName) $ map (AppT (ConT ''StT)) layers
monadBaseControlTransformerInstance
:: Type
-> Dec
monadBaseControlTransformerInstance t =
head $ purifyQ $
[d|
instance MonadBaseControl b m => MonadBaseControl b ($(pure t) m) where
type StM ($(pure t) m) a = ComposeSt $(pure t) m a
liftBaseWith = defaultLiftBaseWith
restoreM = defaultRestoreM
|]
composeExp :: Exp -> Exp -> Exp
composeExp a b =
UInfixE a (VarE '(.)) b