
Gregg Reynolds
On Sun, Mar 1, 2009 at 11:59 AM, Will Ness
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
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
log, 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
_______________________________________________ Beginners mailing list Beginners <at> haskell.org http://www.haskell.org/mailman/listinfo/beginners