module MonadLab.Declarations (
createMonadDecls, createRunDecl,
) where
import Prelude hiding (Monad)
import qualified Prelude (Monad)
import Language.Haskell.TH
import MonadLab.CommonTypes
import MonadLab.Reduction
mkValDecl :: String -> ExpQ -> DecQ
mkValDecl name e = valD (varP $ mkName name) (normalB e) []
createMonadDecls :: MonadName -> Monad -> Q [Dec]
createMonadDecls monadName m = do
typeDecl <- createTypeDecl monadName m
returnDecl <- createReturnDecl monadName m
bindDecl <- createBindDecl monadName m
monadInstanceDecl <- createMonadInstanceDecl monadName m
npmDecls <- createNPMDecls monadName m
return $ typeDecl : monadInstanceDecl : npmDecls
createTypeDecl :: MonadName -> Monad -> DecQ
createTypeDecl monadName m = let tc = getTypeCon m
a = mkName "a"
deM = mkName ("de" ++ monadName)
in tc (varT a) >>= \t -> return $ NewtypeD [] (mkName monadName) [a] (RecC (mkName monadName) [(deM, NotStrict, t)]) []
createMonadInstanceDecl :: MonadName -> Monad -> DecQ
createMonadInstanceDecl monadName m = instanceD (return []) (appT (conT $ mkName "Prelude.Monad") (conT $ mkName monadName)) [createReturnDecl monadName m, createBindDecl monadName m]
createReturnDecl :: MonadName -> Monad -> DecQ
createReturnDecl monadName m = let conM = conE (mkName monadName)
return = getReturn m
in reduceM $ mkValDecl "return" [| $composition $conM $return |]
createBindDecl :: MonadName -> Monad -> DecQ
createBindDecl monadName m = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
bind = getBind m
in reduceM $ mkValDecl ">>=" ([| \x -> \f -> $conM $ $bind ($deM x) ($composition $deM f) |])
createRunDecl :: [Layer] -> MonadName -> RunExpQ -> DecQ
createRunDecl ls monadName run = let deM = dyn ("de" ++ monadName)
in reduceM $ mkValDecl ("run" ++ monadName) [| $composition $run $deM |]
createNPMDecls :: MonadName -> Monad -> Q [Dec]
createNPMDecls monadName m = let lnpms = getLayerNPMs m
in sequence $ concatMap (createLayerNPMDecls monadName) lnpms
where createLayerNPMDecls :: MonadName -> LayerNPM -> [DecQ]
createLayerNPMDecls monadName c@(Io, _) = createIoDecls monadName c
createLayerNPMDecls monadName c@(List, _) = createListMonadDecls monadName c
createLayerNPMDecls monadName c@(ErrorT _ _, _) = createErrorDecls monadName c
createLayerNPMDecls monadName c@(StateT _ _, _) = createStateDecls monadName c
createLayerNPMDecls monadName c@(EnvT _ _, _) = createEnvDecls monadName c
createLayerNPMDecls monadName c@(WriterT _ _, _) = createWriterDecls monadName c
createLayerNPMDecls monadName c@(ContT _, _) = createContDecls monadName c
createStateDecls :: MonadName -> LayerNPM -> [DecQ]
createStateDecls monadName (StateT stateName _, [get, put]) = [createGetDecl monadName stateName get, createPutDecl monadName stateName put, createUpdateDecl monadName stateName]
createGetDecl :: MonadName -> StateName -> NonProperMorphismExpQ -> DecQ
createGetDecl monadName stateName get = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("get" ++ stateName ++ monadName) [| $conM $get |]
createPutDecl :: MonadName -> StateName -> NonProperMorphismExpQ -> DecQ
createPutDecl monadName stateName put = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("put" ++ stateName ++ monadName) [| $composition $conM $put |]
createUpdateDecl :: MonadName -> StateName -> DecQ
createUpdateDecl monadName stateName = let get = dyn ("get" ++ stateName ++ monadName)
put = dyn ("put" ++ stateName ++ monadName)
in mkValDecl ("update" ++ stateName ++ monadName) [| \f -> $get >>= \s -> $put (f s) >> $get |]
createEnvDecls :: MonadName -> LayerNPM -> [DecQ]
createEnvDecls monadName (EnvT envName _, [rdEnv,inEnv]) = [createRdEnvDecl monadName envName rdEnv, createInEnvDecl monadName envName inEnv]
createRdEnvDecl :: MonadName -> EnvName -> NonProperMorphismExpQ -> DecQ
createRdEnvDecl monadName envName rdEnv = reduceM $ mkValDecl ("rd" ++ envName ++ monadName) [| $(conE (mkName monadName)) $ $rdEnv |]
createInEnvDecl :: MonadName -> EnvName -> NonProperMorphismExpQ -> DecQ
createInEnvDecl monadName envName inEnv = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("in" ++ envName ++ monadName) [| \r -> \m -> $conM $ $inEnv r ($deM m) |]
createErrorDecls :: MonadName -> LayerNPM -> [DecQ]
createErrorDecls monadName (ErrorT errorName _, [throw,catch]) = [createThrowDecl monadName errorName throw, createCatchDecl monadName errorName catch]
createThrowDecl :: MonadName -> ErrorName -> NonProperMorphismExpQ -> DecQ
createThrowDecl monadName errorName throw = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("throw" ++ errorName ++ monadName) [| $composition $conM $throw |]
createCatchDecl :: MonadName -> ErrorName -> NonProperMorphismExpQ -> DecQ
createCatchDecl monadName errorName catch = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("catch" ++ errorName ++ monadName) [| \x -> \h -> $conM $ $catch ($deM x) ($composition $deM h) |]
createListMonadDecls :: MonadName -> LayerNPM -> [DecQ]
createListMonadDecls monadName (List, [merge, halt]) = [createMergeDecl monadName merge, createHaltDecl monadName halt]
createMergeDecl :: MonadName -> NonProperMorphismExpQ -> DecQ
createMergeDecl monadName merge = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("merge" ++ monadName) [| \xs -> $conM $ $merge (map $deM xs) |]
createHaltDecl :: MonadName -> NonProperMorphismExpQ -> DecQ
createHaltDecl monadName halt = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("halt" ++ monadName) [| $conM $halt |]
createIoDecls :: MonadName -> LayerNPM -> [DecQ]
createIoDecls monadName (Io, [liftIO]) = [createLiftIODecl monadName liftIO]
createLiftIODecl :: MonadName -> NonProperMorphismExpQ -> DecQ
createLiftIODecl monadName liftIO = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("liftIO" ++ monadName) [| $conM . $liftIO |]
createWriterDecls :: MonadName -> LayerNPM -> [DecQ]
createWriterDecls monadName (WriterT writerName _, [tell, listen, pass]) = [ createTellDecl monadName writerName tell
, createListenDecl monadName writerName listen
, createPassDecl monadName writerName pass
, createCensorDecl monadName writerName
]
createTellDecl :: MonadName -> WriterName -> NonProperMorphismExpQ -> DecQ
createTellDecl monadName writerName tell = let conM = conE (mkName monadName)
in reduceM $ mkValDecl ("tell" ++ writerName ++ monadName) [| $composition $conM $tell |]
createListenDecl :: MonadName -> WriterName -> NonProperMorphismExpQ -> DecQ
createListenDecl monadName writerName listen = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("listen" ++ writerName ++ monadName) [| \m -> $conM ( $listen ($deM m) ) |]
createPassDecl :: MonadName -> WriterName -> NonProperMorphismExpQ -> DecQ
createPassDecl monadName writerName pass = let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("pass" ++ writerName ++ monadName) [| \m -> $conM ( $pass ($deM m) ) |]
createCensorDecl :: MonadName -> WriterName -> DecQ
createCensorDecl monadName writerName = let pass = varE (mkName ("pass" ++ writerName ++ monadName))
in reduceM $ mkValDecl ("censor" ++ writerName ++ monadName) [| \f -> \m -> $pass (m >>= \a -> return (a, f)) |]
createContDecls :: MonadName -> LayerNPM -> [DecQ]
createContDecls monadName (ContT _, [callcc]) = [createCallCCDecl monadName callcc]
createCallCCDecl :: MonadName -> NonProperMorphismExpQ -> DecQ
createCallCCDecl monadName callcc =let deM = dyn ("de" ++ monadName)
conM = conE (mkName monadName)
in reduceM $ mkValDecl ("callcc" ++ monadName) [| \h -> $conM $ $callcc ($deM . (\y -> h ($conM . y))) |]