Can Haskell make distinctions for different kinds of IO

haskell, io

Solution

Yes.

One way to do this is via a custom, restricted `IO` `Monad`. You create a `newtype` wrapper for (transformed) `IO` like so:

newtype MyIO a = My { _runMy :: IO a }

runMy :: MyIO a -> IO a
runMy = _runMy

However, you do NOT expose/export the `My` data constructor. Instead, you expose "wrapped" versions of the operations you want. You also do not expose a `MonadIO` instance (e.g.); that allows unrestricted lifting. You may or may not expose other instances to match `IO`. Basically, external users have to treat `MyIO` as just as opaque as built in IO, with only limited (i.e. restricted) conversion to `MyIO`. You DO expose a `Monad` instance, perhaps the one generated by `GeneralizedNewtypeDeriving`.

You DO expose the `runMy` function, which will allow embedding arbitrary `MyIO` actions inside general `IO` actions, such as at the "top-level" in `main`. You DO NOT directly expose the `_runMy` field, which (together with `return`) would actually provide a "backdoor" lift of:

backdoor :: IO a -> MyIO a
backdoor io = (return () :: MyIO ()) { _runMy = io }
-- polymorphic record update syntax for the win!

That said, most of my pure, total functions don't need to do logging, so I just log where I already have access to IO.

Problem

Disclaimer: My ignorance about Haskell is almost perfect. Sorry if this is really basic, but I couldn't find an answer, or even a question like that. Also my English is not that good. As far as I understand, if I have a function in a system that somehow interacts with filesystem this function must use the IO monad, and will have a type like `IO ()` In my (only business oriented) experience, systems typically interact with filesystem for reading/writing files with business data, AND for logging. And in business application, logging is everywhere. So if I write a system in Haskell (which I wont for a long while), pretty much every function will use the IO monad. Is that the common practice or somehow logging do not requires IO ()? Or maybe Haskell business application do not log that much? Also, how about other types of I/O? if I need to access a database or a web service from a function, this function also uses the IO monad or Haskell also has WS and DB monads? I'm almost sure there is only one IO monad... being able to know the kind of IO just looking at the type looks amazing from my point of view, but I'm sure my point of view is not an objective measure of usefulness...

Original source

Related problems