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
.
runIO
function (discounting unsafePerformIO of course)... – Meditatem 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.) – DoshrunIO
because you cannot run side-effecting code to get a pure answer. Similarly there is no justification for IOT because there is no monad which you can reasonably add IO effects to. In a monad stack IO has to be "innermost" monad - you can add the other monadic effects to it, but not the other way around. – MeditateIOT
without (sensibly) unwrapping internally every time you use bind, which leads to unpredictable behavior? (If yes, maybe make it into a full answer) – DoshrunIOT (launchMissiles >> lift [])
evaluate to? – CinchonidineIOT
is not possible. – SleepingIOT Maybe
can either do an IO action or nothing". However, in such a monad the values would be eitherIOT Just IO a
i.e. an IO action wrapped insideJust
andIOT
or it could beIOT Nothing
. In the latter case you don't haveIO
anymore and your can't really do anything anymore. Basically the behaviour would be that you do computations normally until some error producingNothing
occurs and the program can exit because there's no further work to do. This feels somewhat reasonable but probably not super useful since you can already useexitWith
to similarly exit early. – NonsuitIOT []
can build a list that can later besequence
d". But you don't need transformer forIO
in order tosequence
a list of IO actions. The list monad in Haskell is for non-determinism where you have a computation that branches to multiple results. WithIOT []
you'd have to be able to execute a list of IO actions based on the results of previous IO action lists. What would that mean? The most reasonable interpretation seems that the program would split into multiple threads or processes that run parallel. They'd still share "RealWorld
" so I'm not sure if it's reasonable. – Nonsuit