module MonadLab.Run (
createRun
) where
import Language.Haskell.TH
import Control.Monad
import Prelude hiding (Monad)
import MonadLab.CommonTypes
createRun :: [Layer] -> RunExpQ
createRun cs = do
let listMonad = any (hasLayerType ListLayerType) cs
let contMonad = any (hasLayerType ContLayerType) cs
let ioMonad = any (hasLayerType IoLayerType) cs
paramNames <- mkNames (numRunArgs cs)
let params = map varP paramNames
let args = map varE paramNames
let extractExp = createExtractExp cs
if not contMonad
then do if not listMonad
then if not ioMonad
then lamE params [| $extractExp $(appsE args) |]
else lamE params [| $(appsE args) >>= \v -> return ($extractExp v) |]
else lamE params [| map $extractExp $(appsE args) |]
else do let k = last args
let args' = init args
if not listMonad
then do let k' = [| $k . $extractExp |]
if not ioMonad
then lamE params [| $(appsE (args' ++ [k'])) |]
else lamE params [| $(appsE (args' ++ [ [| return . $k' |] ])) |]
else do let k' = [| (\x -> [x]) . $k . $extractExp |]
lamE params [| $(appsE (args' ++ [k'])) |]
numRunArgs :: [Layer] -> Int
numRunArgs = (1 +) . length . filter (\l -> layerType l == StateLayerType
|| layerType l == EnvLayerType
|| layerType l == ContLayerType)
mkNames :: Int -> Q [Name]
mkNames i = sequence [ newName "q" | _ <- [1..i] ]
createExtractExp :: [Layer] -> ExpQ
createExtractExp = foldr augmentExtractExp [| id |]
where augmentExtractExp :: Layer -> ExpQ -> ExpQ
augmentExtractExp Io e = e
augmentExtractExp List e = e
augmentExtractExp (StateT _ _) e = [| fst . $e |]
augmentExtractExp (EnvT _ _) e = e
augmentExtractExp (ErrorT n _) e = let h = [| \v -> case v of
Left l -> error (n ++ " exception thrown")
Right r -> r
|]
in [| $h . $e |]
augmentExtractExp (WriterT _ _) e = [| fst . $e |]
augmentExtractExp (ContT _) e = e