Diseño de programa modular - Combinación de transformadores de mónada en funciones agnósticas de mónada

Estoy tratando de crear un programa de diseño modular y, una vez más, le pido su ayuda.

Como seguimiento a estas siguientes publicacionesMonad Transformers vs pasar parámetros yDiseño a gran escala en HaskellEstoy tratando de construir dos módulos independientes que utilicen Monad Transformers pero expongan las funciones de Monad-agnostic, luego combinen una función de Monad-agnostic de cada uno de estos módulos en una nueva función de Monad-agnostic.

No he podido ejecutar la función de combinación, p. Ej. como llamomainProgram utilizandorunReaderT en el siguiente ejemplo?

La pregunta secundaria es: ¿existe una mejor manera de lograr el mismo objetivo de diseño modular?

El ejemplo tiene dos módulos simulados (pero se compila), uno que realiza el registro y otro que lee una entrada del usuario y la manipula. La función de combinación lee la entrada del usuario, la registra y la imprime.

{-# LANGUAGE FlexibleContexts #-}

module Stackoverflow2 where

import Control.Monad.Reader

----
---- From Log Module - Writes the passed message in the log
---- 

data LogConfig = LC { logFile :: FilePath }

doLog :: (MonadIO m, MonadReader LogConfig m) => String -> m ()
doLog _ = undefined


----
---- From UserProcessing Module - Reads the user Input and changes it to the configured case
----

data  MessageCase = LowerCase | UpperCase deriving (Show, Read)

getUserInput :: (MonadReader MessageCase m, MonadIO m) => m String
getUserInput = undefined

----
---- Main program that combines the two
----                  

mainProgram :: (MonadReader MessageCase m, MonadReader LogConfig m, MonadIO m) => m ()
mainProgram = do input <- getUserInput
                 doLog input
                 liftIO $ putStrLn $ "Entry logged: " ++ input

Respuestas a la pregunta(2)

Su respuesta a la pregunta