# Difference between revisions of "Let vs. Where"

(use 'select') |
|||

Line 54: | Line 54: | ||

</haskell> |
</haskell> |
||

⚫ | |||

+ | In expression style, you might instead use a [[Case|functional equivalent]] of <hask>case</hask> |
||

+ | in order to represent the guards: |
||

+ | <haskell> |
||

+ | f x = |
||

+ | let a = w x |
||

+ | in select (f (h x a)) |
||

+ | [(cond1 x, a), |
||

+ | (cond2 x, g a)] |
||

+ | </haskell> |
||

+ | |||

+ | Without such a function it looks worse. You would lose the guard structure, |
||

⚫ | |||

<haskell> |
<haskell> |

## Revision as of 13:42, 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, you might instead use a functional equivalent of `case`

in order to represent the guards:

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

Without such a function it looks worse. You would lose the guard structure, 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.