
On 14/09/05, Dhaemon
Hi again, Thanks to everyone for replying. I think I get it now; I was focusing on the wrong aspect of the question. I was totally overlooking referential transparency and the cascade of 'capabilities'(lazyness, etc) it creates. Thus evaluation is just getting values out of expressions, actions(which modify the state of the 'world') are never performed... Except when 'cheating' with monads. Hat-anim is really interesting, I'm playing with it at the moment...
Thanks again, Best regards,
Well, it's not so much that the monads are cheating -- sure, in some sense, the IO monad needs special support to actually run an action that's produced when your program starts, but the cheating that I was referring to was a little backdoor to the runtime system called unsafePerformIO :: IO a -> a. When the expression (unsafePerformIO myAction) gets evaluated, myAction is actually run (and performs any side effects it has) and the result returned. You don't use this under any ordinary circumstances in writing a Haskell program. It's there only for those cases where you have an IO action that's going to compute a pure function, and whose side effects are ignorable (that is, you don't mind if they occur randomly and possibly multiple times), and you can't find another way around it -- this occasionally comes up when making Haskell bindings for C libraries for instance. But it's important to notice that for basically all monads other than IO (or those built on top of IO), even "running" the computations to extract values will have no real world side effects, and so they're effectively just another way to think about and write pure functional code. A small example: sums :: (Num a) => [a] -> [a] -> [a] sums xs ys = do x <- xs y <- ys return (x + y) This code in the list monad, will return all possible sums of pairs of elements from the two input lists, and is certainly a pure function. By just changing the type signature a bit (or removing it), this code can be made to do other related things in other monads. For example, with an appropriate binary tree monad, it will form the binary tree which looks like xs with each (Leaf x) replaced with a copy of ys whose leaves have been incremented by x. No cheating is going on here -- it's just the (purely functional) definitions of return and bind (>>=) for different monads, and the translation of the do-notation into returns and binds that makes this possible. - Cale