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

Lennart Augustsson lennart at augustsson.net
Fri Aug 21 06:01:50 EDT 2009


Internally GHC does have to enforce the ordering on IO operations somehow.
If there actually was a RealWorld value being passed around you could
use some version of seq the guarantees sequential evaluation.
But GHC doesn't even pass a RealWorld around, the sequencing is
enforced by different means.

It's uninteresting for this discussion how GHC enforces the sequencing
internally, the important part is that it is part the sequencing is
part of the IO monad semantics and this is what should be used to
guarantee the sequencing of IO operations in a program.

  -- Lennart

On Thu, Aug 20, 2009 at 10:41 PM, Peter Verswyvelen<bugfact at gmail.com> wrote:
> But how does GHC implement the RealWorld internally? I guess this can't be
> done using standard Haskell stuff? It feels to me that if I would implement
> it, I would need seq again, or a strict field, or some incrementing "time"
> value that is a strict argument of each of the IO primitives. In any case, I
> would need strictness to control the dependencies no? I might be wrong
> (again) but this is all very interesting ;-)
>
> On Thu, Aug 20, 2009 at 10:25 PM, David Menendez <dave at zednenem.com> wrote:
>>
>> 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>
>> <http://www.eyrie.org/~zednenem/>
>
>


More information about the Haskell-Cafe mailing list