Every other monad comes with a transformer version, and from what I know the idea of a transformer is a generic extension of monads. Following how the other transformers are build, IOT
would be something like
newtype IOT m a = IOT { runIOT :: m (IO a) }
for which I could make up useful applications on the spot: IOT Maybe
can either do an IO action or nothing, IOT []
can build a list that can later be sequence
d.
So why is there no IO transformer in Haskell?
(Notes: I've seen this post on Haskell Cafe, but can't make much sense of it. Also, the Hackage page for the ST transformer mentions a possibly related issue in its description, but doesn't offer any details.)
runIO
function (discounting unsafePerformIO of course)...
m a -> a
in the monad interface so I don't see how it is related in the first place. (The internals of bind can be as unsafe as they want as long as the interface is pure.)
IOT
without (sensibly) unwrapping internally every time you use bind, which leads to unpredictable behavior? (If yes, maybe make it into a full answer)
runIOT (launchMissiles >> lift [])
evaluate to?
Consider the specific example of IOT Maybe
. How would you write a Monad
instance for that? You could start with something like this:
instance Monad (IOT Maybe) where
return x = IOT (Just (return x))
IOT Nothing >>= _ = IOT Nothing
IOT (Just m) >>= k = IOT $ error "what now?"
where m' = liftM (runIOT . k) m
Now you have m' :: IO (Maybe (IO b))
, but you need something of type Maybe (IO b)
, where--most importantly--the choice between Just
and Nothing
should be determined by m'
. How would that be implemented?
The answer, of course, is that it wouldn't, because it can't. Nor can you justify an unsafePerformIO
in there, hidden behind a pure interface, because fundamentally you're asking for a pure value--the choice of Maybe
constructor--to depend on the result of something in IO
. Nnnnnope, not gonna happen.
The situation is even worse in the general case, because an arbitrary (universally quantified) Monad
is even more impossible to unwrap than IO
is.
Incidentally, the ST
transformer you mention is implemented differently from your suggested IOT
. It uses the internal implementation of ST
as a State
-like monad using magic pixie dust special primitives provided by the compiler, and defines a StateT
-like transformer based on that. IO
is implemented internally as an even more magical ST
, and so a hypothetical IOT
could be defined in a similar way.
Not that this really changes anything, other than possibly giving you better control over the relative ordering of impure side effects caused by IOT
.
RealWorld
? Is it a nice coincidence that there are (as in exist) transformers of all the other monads we commonly use?IO
was really truly aState
monad whose state value was the entire outside universe, then anIOT
defined as such would work correctly, where "correctly" means that aNothing
inIOT Maybe
would discard the universe and thus end all existence. Personally, I'd stick with the current situation instead...IOT (Just m) >>= k = IOT $ Just $ m >>= maybe (fail "...") id . runIOT . k
? It is bad because(>>=)
canfail
(when it shouldn't)?a
out of aNothing :: Maybe a
which we couldreturn
and thenjoin
, right? Obviously, this would work then forIdentity
, but are there even other monads for which it could possibly work?