Why isn't IO
an instantiation of the (strict) State
monad when we have RealWorld
, as provided in Control.Monad.ST
? I thought RealWorld
were meant to be a magical type representing the reality itself.
I mean, recall the "run" function of the State
monad:
runState :: (s -> (a, s)) -> s -> a
Instantiating this to RealWorld
, we get this:
runIO :: (RealWorld -> (a, RealWorld)) -> RealWorld -> a
Since we cannot construct a value of RealWorld
anyway, this shouldn't act as a backdoor like unsafePerformIO
.
Is the reason because this interpretation would enable the monad transformer IOT
, defined as StateT RealWorld
?
Exposing the RealWorld
in IO
still gives you getUnsafePerformIO :: IO (IO a -> a)
which is just as bad as unsafePerformIO
.
IO
uses unlifted types (RealWorld#
, (#,#)
) to avoid unnecessary allocations, so it doesn't exactly match State
anyway.
It does match ST
, but a direct definition of IO
minimizes the noise whenever you look at Core or need to do some low level hacks (which are much more common than uses of ST
that also involve IO
).
I thought
RealWorld
were meant to be a magical type representing the reality itself.
RealWorld
is a cute name but mostly a source of confusion. It really doesn't represent anything. It's best to forget RealWorld
means anything and think of this definition of IO
only in terms of operational semantics.