[Haskell-cafe] Non-blocking for reactive programs (was: Objects in Haskell)

Graham Klyne GK at ninebynine.org
Mon Nov 29 04:39:16 EST 2004

At 00:39 29/11/04 +0100, Benjamin Franksen wrote:
>One problem remains: to preserve reactivity, the programmer must make sure
>that methods don't execute IO actions that may block indefinitely.
>Unfortunately there is no way in Haskell to enforce this, because
>(indefinitely) blocking IO actions have the same type as non-blocking ones.
>Too late to change that, I guess...

I was somewhat intrigued by this comment.  Maybe I'm missing the point or 
simply too detached from the thrust of this thread to make any sense here, 
but wondered if anything really needs to be changed to be able to express 
this idea of non-blocking IO.

Suppose we define a new type, say NBIO, which, like IO, allows any 
interaction with the external world, but with the proviso that it never 
blocks (I shalln't attempt to try and define exactly what this means, but 
hope that the intent is clear).  A key function associated with this type 
would have type:
     forall a. NBIO a -> IO a

Thus any non-blocking I/O activity can be implemented in NBIO, and its 
IO-equivalent is always available.  But not the converse, of course.


I think I now see the problem:  while functions can be implemented in NBIO, 
and thereby convey an intended guarantee to the caller, there's no way I 
can see for the Haskell type system to stop a programmer to write a 
function of this type that actually uses (but does not return a value from) 
an IO value.  Without this, how can facilities like Debug.Trace be provided?

But then again, if no value from an IO is ever actually used or referenced 
outside the IO code, doesn't lazy evaluation mean that there's never any 
need to evaluate the value within IO?

Now getting hopelessly out of my depth, but interested in any comments you 
may have...


>Btw, here is one of my all-time favourite quotes:
> >>>
>The view of indefinite blocking as a transparent operational property dates
>back to the era of batch-oriented computing, when interactivity was a term
>yet unheard of, and buffering operating systems had just become widely
>employed to relieve the programmer from the intricacies of synchronization
>with card-readers and line-printers. Procedure-oriented languages have
>followed this course ever since, by maintaining the abstraction that a
>program environment is essentially just a subroutine that can be expected to
>return a result whenever the program so demands. Selective method filtering
>is the object-oriented continuation of this tradition, now interpreted as
>``programmers are more interested in hiding the intricacies of method-call
>synchronization, than preserving the intuitive responsiveness of the object
>Some tasks, like the standard bounded buffer, are arguably easier to 
>using selective disabling and queuing of method invocations. But this help is
>deceptive. For many clients that are themselves servers, the risk of becoming
>blocked on a request may be just as bad as being forced into using polling
>for synchronization, especially in a distributed setting that must take
>partial failures into account. Moreover, what to the naive object implementor
>might look like a protocol for imposing an order on method invocations, is
>really a mechanism for reordering the invocation-sequences that have actually
>occurred. In other words, servers for complicated interaction protocols
>become disproportionately easy to write using selective filtering, at the
>price of making the clients extremely sensitive to temporal restrictions that
>may be hard to express, and virtually impossible to enforce.
>(see http://www.cs.chalmers.se/~nordland/ohaskell/rationale.html)

Graham Klyne
For email:

More information about the Haskell-Cafe mailing list