Hi Will,
I can tell I'm talking to a kindred spirit - we oughta be able to describe all this stuff in plain, simple, clear English. It's a great challenge for a prose writer.
>Maybe antilog or prelog or future trace or the like. In any case, I thinkI don't follow. Monad semantics in general is to chain together its action-
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.
functions (:: a -> M b). IO monad's semantics is that it promises to perform
the recorded requests, if called upon. Not only is it directly implicated by
its semantics, it IS its semantics. It is what IO-bind is. Other monad's binds
will mean something else.
To recapture, the only difference IO monad has, is that it refers EXPLICITLY to
a compiler, and its runtime execution operations. But from inside Haskell it's
just anther monad (I've said that already haven't I? :) ).
That's why I propose to call these bind-chainable functions action functions,
not just actions, and actual I/O acivities to call just that, activity. Also
notice I write I/O there where it belongs to the actual world action (... the
terminology really MUST be refined here!). I think anything else is confusing.
I'm open for another suggestion for how to name these "action-functions", but
it's time the definite name is finalized; it's very confusing to see these IO-
action-functions referred to, in all these tutorials, as performing real world
I/O actions. They don't, of course.
Better to avoid "evaluation" altogether (that seems to be your another idea
from that log, is it?).
I think the KEY is to always keep a clear separation of what is inside the pure
Haskell world, and what is executed by its run-time, as an imperative program
iving inside the real volatile world (capable of calling back into Haskell).
And when inside the pure Haskell world, IO monad is ABSOLUTELY in NO RESPECT no
different than any other. The operational log metaphor help keep this part of
its semantics clear, from the other part - the fact that its operational log
will actually get executed by run-time.
Yes there is. There's the whole point I'm driving at. We are not performing a
>> > 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).
computation with our code. We describe the computation that will be performed.
Our values are functions. The usage of actual input is deferred to the runtime
system.
It's just like Show functions that (will) add their output onto a hidden
parameter, the string-being-built (when called). Same here, with the log-being-
built. Assentially, we're dealing here with the delayed application of carried
functions, that's all.
Here's again a simple outline of how an IO monad might look like, inside
Haskell. It helped clarify things for me (dealing with output only, but still):
________________________________
data IO a = IORec -> (a,IORec)-- building the record of I/O activities to be performed
================================
instance Monad IO where
return a rec = (a,rec) -- return :: a -> IO a
(m »= g) rec = uncurry g $ m rec -- g :: a -> IO b
putStrLn :: a -> IO ()
putStrLn a rec = ((),rec ++ [("putStrLn", a)])
Everything is referentially transparent. There are no side effects in Haskell.
> No referential transparency. That's the problem.
You know that. :) You wrote as much yourself (assuming you're the author of
that blog).
_______________________________________
IO value describes the computation that
WILL BE performed OUTSIDE of Haskell.
=======================================
That is a statement that is easy to understand, and is not at all confusing. I
think.
But they are. They describe future computation to be performed outside of
Haskell. Their values - inside Haskell - are one and the same - it's (:: IO a)
entities. Which encapsulate the record, the
_sceleton_of_future_computation_to_be_performed, which is ONE and only. It's
just that it has holes in it, where the actual values will go into. It's like
back into Prolog with its yet-unassigned variables. Or to any imperative
language with set-once.
>Denotationally, all a monad does is ensure sequencing, which is necessary toNo it does more than that. It ascribes actual meaning to what its M-action-
properly order the (non-deterministic) IO values.
functions mean, and it defines what it means for them to be combined in a
chain. They are of course kept in sequence, in that chain.
Right, only better not to use "eval" - ever. Haskell has expressions which get
>With lazy eval this gets translated into the building of a "future log" etc.
reduced; values belong to its runtime system. They are OUTSIDE of Haskell
world.
We do not "evaluate" anything. It would be an imperative. :)
> Thanks,-gregg
Thank you, for a great and enlightening discussion.