Convenience function for discarding logs
Related to https://github.com/co-log/co-log/discussions/224.
I'm not sure if discarding logs is a common enough use-case to warrant this, but I'd like to propose a convenience function:
discardLogs :: LoggerT Message Identity a -> a
discardLogs = (.) runIdentity $ usingLoggerT (mempty :: LogAction Identity Message)
Body of the function is thanks to @chshersh's answer in the discussion. I couldn't figure it out on my own, I appreciate the help!
If this proposal is welcome, I'd be happy to open a pull request for it as well. I assume this would belong in the Colog.Pure module
I'm not sure about adding more functions that work with LoggerT. I wouldn't want to invest in this interface more. With time, it became clear that LoggerT brings more problems than it actually solves. The recommended way to use LogAction in the environment is to have your own ReaderT-like monad. See the following comment for more context:
- https://github.com/co-log/co-log/issues/134#issuecomment-500290507
In case when you have only WithLog constraint for your functions, I would encourage passing LogAction explicitly. This will simplify the code significantly. And if you have some additional IO besides WithLog, such discardLogs function won't work.
Moreover, the proposed discardLogs function doesn't really work if LoggerT is not on the end of your transformer stack.
So, ideally, I'd like to remove LoggerT eventually and that's why I don't want to encourage it. But I don't have a nice migration story at the moment, so LoggerT stays in the library.
However, it's always great to improve documentation 🙂 So if you want to add this function and a usage example to LoggerT or usingLoggerT functions, such contribution would be more than welcome 👍🏻
And if you have some additional IO besides WithLog, such discardLogs function won't work.
I forgot about this scenario. My use-case is that I have pure functions where I wanted to add logging for extra information.
I ended up making monadic functions with only a WithLog constraint, and wanted to keep a completely "pure" version if one wanted to ignore logging (similar to zeroM and zero in #224).
Would it make more sense to change the name from discardLogs to something else?
Moreover, the proposed discardLogs function doesn't really work if LoggerT is not on the end of your transformer stack.
I completely overlooked this as well since my use-case only had a WithLog constraint, whoops!
Here's what I tried changing the type signature to:
discardLogs :: WithLog r msg m => m a -> a
But this no longer compiles. Here's the error:
Couldn't match type 'm' with 'LoggerT Message Identity'.
I assume this is due to m representing any monad, whereas usingLoggerT expects a LoggerT.
How would I be able to avoid LoggerT in my type signature then? I feel like I'm missing something fundamental.
However, it's always great to improve documentation slightly_smiling_face So if you want to add this function and a usage example to LoggerT or usingLoggerT functions, such contribution would be more than welcome 👍🏻
I'd be happy to add it, as well as documentation for it! I hope you don't mind my questions. I'd like to try and move off of LoggerT for reasons you mentioned, but I'm yet again not adequate enough to figure it out on my own 😅
The more I think about it, the more the above signature WithLogs r msg m => m a -> a wouldn't make sense anyways.
If one wants to use IO while discarding logs, it indeed makes more sense to provide a LogAction that does nothing.
The reason I wanted a function like this is, as I mentioned before, I had pure functions where I wanted to add logging to it.
There's no IO or anything else, so the signature LoggerT Message Identity a -> a makes the most sense in my head.
Please let me know if there's something better I could do here!
@qwbarch As I mentioned before, if you only use WithLog constraint, it could be better to just pass LogAction explicitly like this:
zeroM :: Monad m => LogAction m Message -> m Int
And then you'll be able to pass mempty to this function and use runIdentity to unwrap the monad.
However, I see two problems with this suggestion:
- You don't have
HasCallStackpropagated automatically to other functions - You can't use functions like
logInfobecause they expect theWithLogconstraint
There was a similar discussion in another place:
- https://github.com/co-log/co-log-polysemy/issues/2
I'm afraid, I don't have a good answer or suggestion to these problems here. Need to think more about more convenient interface 🤔