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.