On 13/09/05, Dhaemon <dhaemon at gmail.com> wrote:
> Hello,
> I'm quite interested in haskell, but there is something I don't
> understand(intuitively). I've been crawling the web for an answer, but
> nothing talks to me...
> So I was hoping I could find some help here:
> "How is evaluating an expression different from performing action?"
> I'm puzzled... Doesn't it amount to the same thing? Maybe I have a wrong
> definition of "evaluating"(determine the value of an expression)?
> Examples would be appreciated.
> Also, just for kicks, may I had this: I read the code of some haskell-made
> programs and was astonished. Yes! It was clean and all, but there were "do"s
> everywhere... Why use a function language if you use it as an imperative
> one?(i.e. most of the apps in
>http://haskell.org/practice.html)
>> Thanks in advance
>
It should be made clear that the only IO action which is ever actually
performed in a Haskell program is main (short of loading the code up
in an interactive environment and getting it to run other actions
separately). IO actions themselves are described in a pure functional,
referentially transparent way.
Evaluation of an expression is different from performing an IO action
in the various things which can occur as a result. Essentially the
only thing which should be able to occur (without some major cheating)
as the result of evaluating a Haskell expression, is the production of
a value, and this value will always be the same for a given
expression. It should not print things to the screen, fire packets
over the network, read from the random number generator or read or
write to files. (There are instances where IO is lazily delayed until
a result is demanded, so that evaluation of what looks like a pure
list results in reading from a file, but one can only construct these
situations so that they occur inside the execution of an IO action
anyway. The lists aren't really pure.)
The upshot of this is that if one has a Haskell expression, within
time and memory constraints, one can evaluate it on any computer,
under any ordinary circumstances, and get the same result. One can't
make that claim about performing an IO action. IO actions when
performed may read from the keyboard or network or filesystem (as well
as write to the screen, etc.). However, evaluation of an expression
which represents an IO action always yields the same action (even if
that action may not do the same thing when it is actually performed in
the end). That's the distinction that's being made.
As it has been pointed out in other posts, do notation is pure, in the
sense that do blocks are expressions which evaluate to the same thing
every time. This thing may be an IO action, but it may also be a list,
a Maybe value, a binary tree, a function of type s -> (a, s) (called a
state computation), a graph, or any number of other monadic types.
Most monads m are not "one-way" in that one can extract results from
the monadic containers - there usually exist functions (m a -> a) --
IO is a major example of a case where this doesn't hold, but it's by
far not the only example of a monad.
- Cale