# Let vs. Where

### From HaskellWiki

(Difference between revisions)

(change "=" to "->") |
(Improved lay-out) |
||

Line 129: | Line 129: | ||

fib' n = fib (n - 1) + fib (n - 2) | fib' n = fib (n - 1) + fib (n - 2) | ||

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

− | you will notice, that the second one runs considerably slower than the first one. | + | you will notice, that the second one runs considerably slower than the first one. You may wonder, why just adding the explicit argument to <hask>fib</hask> (known as [[eta expansion]]) reduces the performance dramatically. |

− | You may wonder, why just adding the explicit argument to <hask>fib</hask> (known as [[eta expansion]]) | + | |

− | reduces the performance dramatically. | + | |

You might see the reason better, if you rewrite this code using <hask>let</hask>. | You might see the reason better, if you rewrite this code using <hask>let</hask>. | ||

Line 150: | Line 148: | ||

in map fib' [0 ..] !! x | in map fib' [0 ..] !! x | ||

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

− | . In the second case <hask>fib'</hask> is (re-)defined for every argument <hask>x</hask>, | + | . In the second case <hask>fib'</hask> is (re-)defined for every argument <hask>x</hask>, thus it cannot be floated out.<br><br> |

− | thus it cannot be floated out. | + | |

In contrast to that, in the first case <hask>fib'</hask> can be moved to the top level by a compiler. | In contrast to that, in the first case <hask>fib'</hask> can be moved to the top level by a compiler. | ||

The <hask>where</hask> clause hid this structure | The <hask>where</hask> clause hid this structure |

## Revision as of 06:11, 24 October 2012

Haskell programmers often wonder whether to uselet

where

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 thatlet ... in ...

where

## Contents |

## 1 Advantages of let

Suppose you have the function

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

Control.Monad.State

However, transforming to

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

where

f =

x

let

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

case

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)

where

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

let

where

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

fib

let

Compare

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

fib'

x

In contrast to that, in the first case

fib'

where

x

- Haskell-Cafe on Eta-expansion destroys memoization?