[Haskell-cafe] Re: Where do I put the seq?

David Menendez dave at zednenem.com
Thu Aug 20 16:25:33 EDT 2009

On Thu, Aug 20, 2009 at 3:43 PM, Peter Verswyvelen<bugfact at gmail.com> wrote:
> Also doesn't Haskell's IO system uses a hidden RealWorld type that has no
> value but which is passed from between monadics binds in a strict way to
> make the ordering work?

Haskell only describes how the IO monad behaves. GHC's implementation
uses a RealWorld type, but other implementations are possible.

A quick sketch of an alternative implementation,

data Trace = Done | Get (Char -> Trace) | Put Char Trace

newtype IO a = IO { unIO :: (a -> Trace) -> Trace }

instance Monad IO where
    return a = IO (\k -> k a)
    m >>= f = IO (\k -> unIO m (\a -> unIO (f a) k))

getChar :: IO Char
getChar = IO Get

putChar :: Char -> IO ()
putChar c = IO (\k -> Put c (k ()))

The run-time system is responsible for interpreting the Trace and
inputting/outputting characters as needed. All of IO can be
implemented in this manner.

> So IO in Haskell is a horrible hack then? :-) If it
> would be done nicely, in the FRP way, then RealWorld IO would need time
> stamps to get rid of the hack?

Again, no. GHC's IO type uses the RealWorld value to create data
dependencies. For example, putChar 'x' >> getChar, the getChar depends
on the RealWorld returned by putChar 'x'.

This is why it's dangerous to open up GHC's IO type unless you know
what you're doing. If you aren't careful, you may accidentally
duplicate or destroy the RealWorld, at which point you risk losing
purity and referential transparency.

I suppose you could consider the fact that GHC's IO is implemented
using impure primitive operations a hack, but the whole point of the
IO monad is to hide that impurity from the rest of the program.

Dave Menendez <dave at zednenem.com>

More information about the Haskell-Cafe mailing list