
Hi, Bryan Vicknair wrote:
I have a bunch of little database IO functions. Each does something to the database, and returns a log string describing what it did, and possibly a meaningful result from the database.
query :: IO (String, a) update :: a -> IO (String, ())
...and a few functions that orchestrate all the little functions into doing useful work.
syncWeek :: Week -> IO () syncAll : : IO ()
I don't want the individual functions to know what is done with the log string describing what they did. Top-level orchestrating functions should make that decision, which can be one of:
1) Collect and print all to a log once all computations are done. 2) Print to stdout *as each computation is run*. 3) Ignore them.
Instead of using an existing monad transformer, I would consider to write my own set of logging monad transformers. This could give you this interface: class MonadLog m where log :: String -> m () query :: (MonadIO m, MonadLog m) => m a update :: (MonadIO m, MonadLog m) => a -> m () And then you can provide different implementations for MonadLog: newtype IgnoreLogT m a = IgnoreLogT { runIgnoreLogT :: m a } instance MonadLog (IgnoreLogT m) where log _ = return () newtype ConsoleLogT m a = ConsoleLogT { runConsoleLogT :: m a } instance MonadIO m => MonadLog (ConsoleLogT m) where log msg = liftIO (putStrLn msg) newtype StringLogT m a = StringLogT { runStringLogT :: WriterT String m a } instance MonadLog (StringLogT m) where log msg = StringLogT $ tell msg Tillmann