On Sun, Mar 1, 2009 at 11:59 AM, Will Ness <will_n48@yahoo.com> wrote:
 
The IO-action is not the I/O operation in the real world, but an action of
recording a promise to perform it.

Any IO primitive can be seen as latching this hidden promise onto its explicit
return value, thus creating a monadic value (:: IO a), carrying along this
hidden promise. IO bind combines these promises into a combined record, or log,
of promises to perform actual I/O activity, if called upon by the system.

That recording of a promise is the IO-action that IO monad is about, from pure
Haskell standpoint.

Ok, I kinda like the idea of accumulating a "log" of promised actions, although I'd suggest a different term since log usually means history.  Maybe antilog or prelog or future trace or the like.  In any case, I think that's useful for explaining lazy evaluation, but it's not directly implicated by monad semantics.  IOW monad semantics and evaluation strategy are (mostly) orthogonal. 
 
Another monad will have another meaning for its actions, latching another
hidden data on their results, but they still can be seen as actions, in context
of being sequenced and combined by that monad's bind.

I see, you're thinking of action as something like the promised eval.  As opposed to the action of performing actual IO.  I fear that might confuse newcomers, though; probably better to stick with "function" terminology and discuss evaluation separately. 

> Correction:  special name for IO "functions" (actually "IO terms" would be
better). 


Why? They are just fuctions, of type (Monad m => a -> m b). What I'm saying,
they are of special type, chainable by the M monad, so it seems logical to have
a special name for such M-chainable functions, e.g. "M-action functions"
(whatever the M).

Technically they cannot be functions - there's no "same input, same output" (at least not for input operations).  No referential transparency.  That's the problem.
 
>
> This was a big problem for me; I find terms
like "action", "computation", "function" completely misleading for IO
terms/values. 


Why? A function of type (a -> M b) is a function that returns a value, (:: M
b), tagged with some monadic hidden data. In case of IO, it is a promise to
perform some actual I/O that's passed around, hidden. But the M-action function
itself is just a regular Haskell function. It can be defined elsewhere,
anywhere.

But the "promise to perform" is a matter of evaluation semantics, not denotational semantics.  Denotationally these things cannot be functions.

I saw your other note too.  I think the idea that the runtime builds a "future log" is useful - simple and pretty easy to grok.  But I would recommend keeping a clear distinction between Haskell's language semantics (denotational) and its compiler/runtime semantics (evaluational).  Denotationally, all a monad does is ensure sequencing, which is necessary to properly order the (non-deterministic) IO values.  With lazy eval this gets translated into the building of a "future log" etc.

Thanks,

-gregg