Tony,

> I thought Paul Hudak's seminal paper 'On the Expressiveness of Purely
> Functional I/O Systems' had shown that stream I/O was COMPLETELY equivalent
> to continuation I/O. Or is the emphasis above to be taken to be on the word
> 'efficiently'?

Consider a polymorphic continuation request such as the following:

    someRequest :: T a -> (U a -> Dialogue)

where T and U are type constructors such that type a is a component of types
T a and U a.

Translating to a stream model we get:

    type Dialogue = [Response] -> [Request]

    data Request
       = ...
       | SomeRequest (T a)

    data Response
       = ...
       | SomeResponse (U a)
                         :
                         |
                         We need existential types to allow this

and then when we cannot safely extract the (U a) from a SomeResponse.  All that
we can safely do to the (U a) is apply a function to it, the function being an
additional argument to the SomeResponse constructor, i.e.

    data Response
       = ...
       | SomeResponse (U a) (U a -> Dialogue)

And where does this function come from?  Of course we must supply it as part of
the request, unless the run-time system is very clever and knows what we want
to do next!  So we get:

    data Request
       = ...
       | SomeRequest (T a) (U a -> Dialogue)

    type Dialogue = Request

Oops!  We seem to have discovered that if we wish to have polymorphic requests,
and have type safety, we must use some form of continuation I/O.

Note: if the language does not provide existential types, the Request data type
is invalid, and must instead be made an implementation-defined abstract data
type.
_______________________________________________________________________________

[EMAIL PROTECTED]          Evan Ireland, Department of Computer Science,
 +64-6-3569099 x8541          Massey University, Palmerston North, New Zealand.

Reply via email to