# Let vs. Where

### From HaskellWiki

m |
m |
||

Line 2: | Line 2: | ||

This seems to be only a matter of taste in the sense of "[[Declaration vs. expression style]]", however there is more to it. |
This seems to be only a matter of taste in the sense of "[[Declaration vs. expression style]]", however there is more to it. |
||

− | It is important to know that <hask>let ... in ...</hask> is an expression, |
+ | It is important to know that <hask>let ... in ...</hask> is an expression, that is, it can be written wherever expressions are allowed. In contrast, <hask>where</hask> is bound to a surrounding syntactic construct, like the [[pattern matching]] line of a function definition. |

− | that is, it can be written wherever expressions are allowed. |
||

− | In contrast, <hask>where</hask> is bound to a surrounding syntactic construct, like the [[pattern matching]] line of a function definition. |
||

== Advantages of let == |
== Advantages of let == |
||

− | Consider you have the function |
+ | Suppose you have the function |

<haskell> |
<haskell> |
||

f :: s -> (a,s) |
f :: s -> (a,s) |

## Revision as of 21:49, 8 August 2011

Haskell programmers often wonder whether to useThis seems to be only a matter of taste in the sense of "Declaration vs. expression style", however there is more to it.

It is important to know that## Contents |

## 1 Advantages of let

Suppose you have the function

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

However, transforming to

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

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

## 2 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

f x = let a = w x in case () of _ | cond1 x = a | cond2 x = g a | otherwise = f (h x a)

or a functional equivalent:

f x = let a = w x in select (f (h x a)) [(cond1 x, a), (cond2 x, g a)]

or a series of if-then-else expressions:

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

## 3 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)

## 4 Problems with where

If you run both

fib = (map fib' [0 ..] !!) where fib' 0 = 0 fib' 1 = 1 fib' n = fib (n - 1) + fib (n - 2)

and

fib x = map fib' [0 ..] !! x where fib' 0 = 0 fib' 1 = 1 fib' n = fib (n - 1) + fib (n - 2)

you will notice, that the second one runs considerably slower than the first one.

You may wonder, why just adding the explicit argument toreduces the performance dramatically.

You might see the reason better, if you rewrite this code usingCompare

fib = let fib' 0 = 0 fib' 1 = 1 fib' n = fib (n - 1) + fib (n - 2) in (map fib' [0 ..] !!)

and

fib x = let fib' 0 = 0 fib' 1 = 1 fib' n = fib (n - 1) + fib (n - 2) in map fib' [0 ..] !! x

thus it cannot be floated out.

In contrast to that, in the first case- Haskell-Cafe on Eta-expansion destroys memoization?