Hacker News new | ask | show | jobs
by literon 4606 days ago
I don't think the "Xy monad will taint all your code" stands.

I used to think that too, but if you have monadic code M and pure code P, if you need to tie P to M (say at a third callsite C), you just lift the P into the monad at C, and that's it. P stays pure, C of course gets monadic, but that is since it _is_ monadic.

Now logging: I guess people overpanic this. There are two separate sides of logging I think:

1) Effect logging: If you want to log effects (going to send the email, etc), you are already in IO, no worries.

2) App logic logging: This is more like debug-logging to verify that you logic works and flows as expected. If you need this in pure code, throw in a Writer monad for logging the stuff (can discard it if not needed).

2a) Eventually you'll get somewhere where you have IO, so you can dump the aggregated logs if you want.

2b) Or just use unsafePerformIO to send to a logging thread (beat me with a stick).

As a bonus, for app logging you might use a proper ADT for your log statements instead of string, which is great for testing, and even greater for persisting (in json, protobuf, whatever) and later inspection.

1 comments

I am aware of lifting, but the question is if you have monadic code and pure code in different modules (or you need to go through function which was previously pure), where do you put the lift? If you put it outside the module, you break the modularity. If you put it inside, well then you might as well make the functions monadic in the first place. Basically if you have functions in module API (which may be in itself pure) that may eventually end up calling unpure functions, you have to provision for that somehow, either in the module by making them monadic, or in the caller via lifting. Either way, it's not as clean as it could be.

But I thought about it some more, and to me it seems that actually parametrizing the functions to outside world is not that bad; it's a kind of dependency injection, and seems fine. What is really problematic is returning all the IOs (or other monads) from them; especially since you cannot curry return parameters just like you can entry parameters. So even if that could be replaced by some other mechanism, it would be helpful.

But I didn't know unsafePerformIO, sounds like it can be helpful in some cases.