[Haskell-cafe] Expanding do notation

Chris Kuklewicz haskell at list.mightyreason.com
Sat Jan 7 14:23:40 EST 2006


Mmmm...now I had to go look it up.

David F. Place wrote:
> Hi Chris,
> 
> Yes, this is just what I need to understand.  Could you point me to a 
> description of this?  I couldn't find any discussion of it in the 
> reference document.  Thanks.
> 
> Cheers, David
> 
> On Jan 7, 2006, at 12:25 PM, Chris Kuklewicz wrote:
> 
>> the mind-bending-thing I had to learn with Haskell is that the "let  p ="
>>  creates source code *shorthand*.
> 

This is the first time I have tried to explain this.  So it will not
help much...

The mantra is : Bindings are not variables

The best, official thing to read is section 3.12 of the Haskell98 Report:

http://www.haskell.org/onlinereport/exps.html#sect3.12

It shows that "let p = foo
                   q = bar
               in ..."

is translated to

"let (~p,~q) = (foo,bar) in ..."

which is translated to

"case (foo,bar) of
  ~(~p, ~q) -> ..."

Assuming it does not refer to iteself, otherwise it becomes

"let (~p,~q) = fix (\ ~(~p,~q) -> (foo,bar) ) in ... "

which is translated to

"case fix (\ ~(~p,~q) -> (foo,bar) ) of
   ~(~p, ~q) -> ..."

At which point you are in section "3.13 Case Expressions"

So "let p = permutation [1..n]" merely pattern matches the bound name
"p" to the value that "permutations [1..n]" lazily evaluates to.

In Scheme/Lisp the let would allocate a specific cell "p" that would
point to the strictly evaluated result of "permutations [1..n]".

This Haskell pattern binding is the key to being referentially
transparent.  It means there is no difference between "p" and
"permutations [1..n]".  Allocating a memory cell for "p" would be an
observable difference, thus Haskell does no allocation.

This also means you can do this:

let a = 1
    b = 2
    c = 3
    d = a+b+c
in a*b*c*d

without it having to allocate all those variables, because they are
shorthand, NOT VARIABLES.  All bindings are constant, so the compiler
can substitute / inline them and never specifically allocate
intermediate stoage, thus "a,b,c,d" are not allocated.

This lets you break up a big function into many small expressions with
sensible names, and perhaps reuse the pieces.

Thus "map/foldl/filter/..."

-- 
Chris


More information about the Haskell-Cafe mailing list