嵌套Monad Transform的典型App

#Haskell

import Control.Monad.Writer import Control.Monad.State import Control.Monad.Trans

data Model = Model
    { a :: Int
    , b :: Int
    } deriving (Show)

newtype App a = App
    { runApp :: StateT Model (WriterT [String] IO) a 
    } deriving
        ( Functor
        , Applicative
        , Monad
        , MonadState Model
        , MonadWriter [String]
        , MonadIO
        )

execApp :: Model -> App a -> IO a
execApp model app = do
    ((ret, newState), log) <- runWriterT (runStateT (runApp app) model)
    putStrLn $ show log
    putStrLn $ show newState
    return ret

appMain :: App String
appMain = do
    tell ["init"]
    put Model {a = 1, b = 2}
    liftIO $ putStrLn "init"
    input <- liftIO $ getLine
    return input

main = do
    input <- execApp (Model {a = -1, b = -2}) appMain
    putStrLn input
    return ()