There have been claims that the IO
monad has no monad transformer, or even cannot have a monad transformer. Why is there no IO transformer in Haskell?
First question: Then, what is this code? https://hackage.haskell.org/package/acme-iot-0.1.0.1/docs/Control-Monad-Trans-IO.html Is this not a monad transformer for IO
, "adding IO
capabilities to any monad" as the documentation says?
Second question: There is this blog post: http://h2.jaguarpaw.co.uk/posts/io-transformer/ where it is claimed that IOT m a = (forall x. m x -> IO x) -> IO a
is a monad transformer for IO
applied to an arbitrary foreign monad m
. It is assumed, however, that the functions of type m x -> IO x
must be monad morphisms. The blog post elaborates on this to show that (at least) the monad morphism laws hold for the map m a -> IOT m a
.
Now, this construction seems to apply to arbitrary monads and seems to give a formula for a monad transformer for a completely arbitrary base monad Base a
. The monad transformer BaseT
is defined by:
BaseT base m a = (forall x. m x -> base x) -> base a
Here the functions of type forall x. m x -> base x
are assumed to be monad morphisms. (The code does not express that requirement in the type.)
Does this formula give a completely general monad transformer for any base monad base
and any foreign monad m
?
Are there monad morphisms lift: m a -> BaseT base m a
and hoist :: (forall x. m x -> n x) -> BaseT base m a -> BaseT base n a
?
Are there any other laws that a monad transformer must satisfy and BaseT
does not satisfy?
One of my misgivings about BaseT
is that the type forall x. m x -> base x
could be void, for some m
and base
, even if we do not assume that it must be a monad morphism. There are some monads m
and base
for which there are simply no natural transformations of type forall x. m x -> base x
, for example, m a = Maybe a
and base a = a
. So, in that case, the void type gets substituted into the formula and we get BaseT base m a = Void -> m a
, which is equivalent to Unit
. A monad transformer that is identically equal to Unit
is useless for practical applications but does satisfy the monad morphism laws (as Unit
is a lawful monad and any other monad can be mapped to Unit
by a monad morphism). So, BaseT base m
may not give a useful answer for some base
and m
. Does it mean that it is nevertheless useful when base = IO
?
acme-iot
, as its name implies, is a joke package. It breaks purity. The following program prints when a value is forced (which would require unsafeInterleaveIO
or unsafePerformIO
).
module Main where
import Control.Monad.Trans.IO
import Control.Monad.Trans.Class
e :: IOT [] ()
e = do
x <- lift [1,2]
sequenceIO [print (x :: Int)]
main :: IO ()
main = do
_ <- runIOT e -- prints nothing
[a,b] <- runIOT e -- a, b :: () -- prints nothing
b `seq` pure () -- prints 2 (even though () `seq` pure () should be equal to pure ())
a `seq` pure () -- prints 1
The notion of "a monad transformer for a particular monad" is not well-defined. One may be "a monad transformer t
such that t Identity
is isomorphic to IO
", and the generic construction you point out does satisfy that definition. The myth that there is no "IO monad transformer" comes from a mix of (1) if you make strong enough requirements for what that even means it may indeed not exist, (2) when it does exist, there may be no use case for such a thing.
Another generic construction that may be relevant is the free monad transformer. FreeT IO
is a monad transformer and it has IO in it.