It might just be easiest for me to explain than to find another resource:
"let" and "where" are both ways of creating local variables in a function. They
serve similar purposes, and in most cases, it's your choice of which one to
use. (Comparing to C++, the choice of let vs. where is not too far from the
choice between while(…) { … } and do { … } while(…). There are differences, but
they're more a matter of style than anything else.) Further complicating this,
in Haskell, is that there are two forms of "let": one that appears with "do"
notation and one that appears independent of "do". So, we will tackle the three
forms ("let … in", "where", and "let" with "do") separately:
Normal "let":
In a function (which does not use "do"), you can use "let" to make local
variables. The word "in" separates the local variable declaration from the part
of your function where you want to use that variable. Loosely translating from
Haskell to C++:
Haskell:
> let foo = bar in baz
C++:
> /* insert correct type here */ foo = bar;
> baz
In both languages, the variable foo is available while executing baz.
Haskell allows multiple variable declarations lumped together in one "let", for
convenience. These variables do not have to have the same type.
> let foo1 = bar1
> foo2 = bar2
> in
> baz
In this last example, the "let" declares both foo1 and foo2, and you can use
these variables in baz (and in bar1 and bar2, if you really want). Note that
here is a place where indentation matters -- foo2 has the same indentation
level as foo1. The "in" can appear on the same line as the last variable
declaration or not, at your choosing.
This form of "let" (the one outside of "do") *always* needs an "in".
"where":
At the end of a function clause definition (a function clause is one branch of
a function that does argument pattern-matching), you can insert a "where"
section to declare local variables in that clause.
> some_function x =
> do_cool_thing a b
> where
> a = blah x
> b = something_long_and_complicated
Here, a and b are available in the body of the function (and throughout the
"where" clause). This would be equivalent to
> some_function x =
> let a = blah x
> b = something_long_and_complicated
> in do_cool_thing a b
It's best to use descriptive variable names with "where", because it can be
hard to read code that uses "where" and poor variable names, as the definitions
of the variables comes after their use.
"where" can also be used in other contexts, but I don't want to over-complicate
things here -- this is the most common place for "where".
"let" in "do":
Using "do" notation, you can use "let" much like a normal "let", but this "let"
has no "in". The variables declared by the "let" scope over the remainder of
the "do" block.
> some_fun x = do
> c <- something_monadic x
> let a = pure_function c
> another_monadic_thing c a
Here, the variable "a" is available in the last line. Note that there is no
"in". This form of "let" can also, declare multiple new variables, just like
the other one. It still does not have "in".
I hope this all helps!
Richard
On Apr 1, 2013, at 11:16 AM, A Smith wrote:
> Hi
> I think I've mastered much of functional programming with Haskell, or at
> least I can write programs which process as desired.
> However the existence of the "let" statement evades me apart from a quick
> way to define a function. Then there is the "in" and "where" parts. Its been
> suggested its to do with scope and is obvious. I think I need to understand
> it in a C/C++/Perl style of code to have a Eureka moment when it will be
> obvious.
> Can someone refer me to something which will assist me ?
>
> Andrew _______________________________________________
> Haskell-Cafe mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe