(ab)use compiler optimization

Hello, To analyse, test, and debug my system I use a WriterT for logging. The log file created can be quite large and a lot of 'Log' is created in memory, too. I thought, that maybe I can (ab)use the compiler to switch logging on and off as needed before compiling. I tried to either always return an empty Log when running the WriterT, or just always ignore logging depending on a constant and hoped GHC to optimize the logging away. _NOLOGGING = True runWT :: (Monad m) => (WriterT Log m a) -> m (a, Log) runWT m | _NOLOGGING = runWriterT m empty >>= \(a,_) -> return (a,emptyLog ) | otherwise = runWriterT m emptyLog logging :: Message -> WriterT Log m () logging msg = if _NOLOGGING then return () else tell msg However, according to the heap profile there is still a lot of 'Log' in the memory. So, is this possible this way at all and if not, is there another (apart from removing all logging by hand). Thanks

Martin Hofmann wrote:
I thought, that maybe I can (ab)use the compiler to switch logging on and off as needed before compiling. I tried to either always return an empty Log when running the WriterT, or just always ignore logging depending on a constant and hoped GHC to optimize the logging away.
_NOLOGGING = True
runWT :: (Monad m) => (WriterT Log m a) -> m (a, Log) runWT m | _NOLOGGING = runWriterT m empty >>= \(a,_) -> return (a,emptyLog ) | otherwise = runWriterT m emptyLog
logging :: Message -> WriterT Log m () logging msg = if _NOLOGGING then return () else tell msg
However, according to the heap profile there is still a lot of 'Log' in the memory. So, is this possible this way at all and if not, is there another (apart from removing all logging by hand).
Most likely, the WriterT monad is still constructing a log, except that it now looks like emptyLog `mappend` emptyLog `mappend` ... etc. Of course, this is equal to emptyLog but it's never evaluated and these huge expressions are eating up memory. I think that importing WriterT from Control.Monad.Writer.Strict should solve the problem. With that, you can revert to runWT = runWriterT as well, only logging needs to be implemented as you did. Another method, which is guaranteed to work, is to implement a minuscule custom logging monad like this: module Logger where type Logger m a = WriterT Log m a runLogger = runWriterT logging = tell and replace it with module MockLogger where type Logger m a = m a runLogger = fmap $ \a -> (a,emptyLog) logging = const $ return () when you don't want to log anything. Regards, apfelmus -- http://apfelmus.nfshost.com
participants (2)
-
Heinrich Apfelmus
-
Martin Hofmann