[Haskell-cafe] Re: Functional vs Imperative

Cale Gibbard cgibbard at gmail.com
Wed Sep 14 20:35:11 EDT 2005


On 14/09/05, Dhaemon <dhaemon at gmail.com> wrote:
> 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


More information about the Haskell-Cafe mailing list