Difference between revisions of "Let vs. Where"

From HaskellWiki
Jump to navigation Jump to search
(let is an expression)
 
Line 7: Line 7:
 
In contrast to that, <hask>where</hask> is bound to a surrounding syntactic construct,
 
In contrast to that, <hask>where</hask> is bound to a surrounding syntactic construct,
 
like the [[pattern matching]] line of a function definition.
 
like the [[pattern matching]] line of a function definition.
  +
  +
== Advantages of let ==
   
 
Consider you have the function
 
Consider you have the function
Line 39: Line 41:
 
</haskell>
 
</haskell>
   
  +
== Advantages of where ==
   
  +
Because "where" blocks are bound to a syntactic construct, they can be used to share bindings between parts of a function that are not syntactically expressions. For example:
  +
  +
<haskell>
  +
f x
  +
| cond1 x = a
  +
| cond2 x = g a
  +
| otherwise = f (h x a)
  +
where
  +
a = w x
  +
</haskell>
  +
  +
In expression style, the guard structure would be lost, and the heavier lexemes arguably make the resulting function harder to read:
  +
  +
<haskell>
  +
f x
  +
= let a = w x
  +
in if cond1 x
  +
then a
  +
else if cond2 x
  +
then g a
  +
else f (h x a)
  +
</haskell>
  +
  +
== Lambda Lifting ==
  +
  +
One other approach to consider is that let or where can often be implemented using [[lambda lifting]] and [[let floating]], incurring at least the cost of introducing a new name. The above example:
  +
  +
<haskell>
  +
f x
  +
| cond1 x = a
  +
| cond2 x = g a
  +
| otherwise = f (h x a)
  +
where
  +
a = w x
  +
</haskell>
  +
  +
could be implemented as:
  +
  +
<haskell>
  +
f x = f' (w x) x
  +
  +
f' a x
  +
| cond1 x = a
  +
| cond2 x = g a
  +
| otherwise = f (h x a)
  +
</haskell>
   
  +
The auxilliary definition can either be a top-level binding, or included in f using let or where.
   
 
[[Category:Style]]
 
[[Category:Style]]

Revision as of 03:00, 14 November 2007

Haskell programmers often wonder, whether to use let or where. This seems to be only a matter of taste in the sense of "Declaration vs. expression_style", however there is more about it.

It is important to know that let ... in ... is an expression, that is, it can be written whereever expressions are allowed. In contrast to that, where is bound to a surrounding syntactic construct, like the pattern matching line of a function definition.

Advantages of let

Consider you have the function

f :: s -> (a,s)
f x = y
   where y = ... x ...

and later you decide to put this into the Control.Monad.State monad. However, transforming to

f :: State s a
f = State $ \x -> y
   where y = ... x ...

will not work, because where refers to the pattern matching f =, where no x is in scope.

In contrast, if you had started with let, then you wouldn't have trouble.

f :: s -> (a,s)
f x =
   let y = ... x ...
   in  y

This is easily transformed to:

f :: State s a
f = State $ \x ->
   let y = ... x ...
   in  y

Advantages of where

Because "where" blocks are bound to a syntactic construct, they can be used to share bindings between parts of a function that are not syntactically expressions. For example:

f x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)
  where
    a = w x

In expression style, the guard structure would be lost, and the heavier lexemes arguably make the resulting function harder to read:

f x
  = let a = w x
    in if cond1 x
       then a
       else if cond2 x
       then g a
       else f (h x a)

Lambda Lifting

One other approach to consider is that let or where can often be implemented using lambda lifting and let floating, incurring at least the cost of introducing a new name. The above example:

f x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)
  where
    a = w x

could be implemented as:

f x = f' (w x) x

f' a x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)

The auxilliary definition can either be a top-level binding, or included in f using let or where.