Haskell: Where vs. Let - haskell

I am new to Haskell and I am very confused by Where vs. Let. They both seem to provide a similar purpose. I have read a few comparisons between Where vs. Let but I am having trouble discerning when to use each. Could someone please provide some context or perhaps a few examples that demonstrate when to use one over the other?
Where vs. Let
A where clause can only be defined at the level of a function definition. Usually, that is identical to the scope of let definition. The only difference is when guards are being used. The scope of the where clause extends over all guards. In contrast, the scope of a let expression is only the current function clause and guard, if any.
Haskell Cheat Sheet
The Haskell Wiki is very detailed and provides various cases but it uses hypothetical examples. I find its explanations too brief for a beginner.
Advantages of Let:
f :: State s a
f = State $ \x -> y
where y = ... x ...
Control.Monad.State
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.
Haskell Wiki on Advantages of Let
f :: State s a
f = State $ \x ->
let y = ... x ...
in y
Advantages of Where:
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)
Declaration vs. Expression
The Haskell wiki mentions that the Where clause is declarative while the Let expression is expressive. Aside from style how do they perform differently?
Declaration style | Expression-style
--------------------------------------+---------------------------------------------
where clause | let expression
arguments LHS: f x = x*x | Lambda abstraction: f = \x -> x*x
Pattern matching: f [] = 0 | case expression: f xs = case xs of [] -> 0
Guards: f [x] | x>0 = 'a' | if expression: f [x] = if x>0 then 'a' else ...
In the first example why is the Let in scope but Where is not?
Is it possible to apply Where to the first example?
Can some apply this to real examples where the variables represent actual expressions?
Is there a general rule of thumb to follow when to use each?
Update
For those that come by this thread later on I found the best explanation to be found here: "A Gentle Introduction to Haskell".
Let Expressions.
Haskell's let expressions are useful
whenever a nested set of bindings is
required. As a simple example,
consider:
let y = a*b
f x = (x+y)/y
in f c + f d
The set of bindings created by a let
expression is mutually recursive, and
pattern bindings are treated as lazy
patterns (i.e. they carry an implicit
~). The only kind of declarations
permitted are type signatures,
function bindings, and pattern
bindings.
Where Clauses.
Sometimes it is convenient to scope
bindings over several guarded
equations, which requires a where
clause:
f x y | y>z = ...
| y==z = ...
| y<z = ...
where z = x*x
Note that this cannot be done with a let expression, which only scopes over the expression which it encloses. A where clause is only allowed at the top level of a set of equations or case expression. The same properties and constraints on bindings in let expressions apply to those in where clauses. These two forms of nested scope seem very similar, but remember that a let expression is an expression, whereas a where clause is not -- it is part of the syntax of function declarations and case expressions.

1: The problem in the example
f :: State s a
f = State $ \x -> y
where y = ... x ...
is the parameter x. Things in the where clause can refer only to the parameters of the function f (there are none) and things in outer scopes.
2: To use a where in the first example, you can introduce a second named function
that takes the x as a parameter, like this:
f = State f'
f' x = y
where y = ... x ...
or like this:
f = State f'
where
f' x = y
where y = ... x ...
3: Here is a complete example without the ...'s:
module StateExample where
data State a s = State (s -> (a, s))
f1 :: State Int (Int, Int)
f1 = State $ \state#(a, b) ->
let
hypot = a^2 + b^2
result = (hypot, state)
in result
f2 :: State Int (Int, Int)
f2 = State f
where
f state#(a, b) = result
where
hypot = a^2 + b^2
result = (hypot, state)
4: When to use let or where is a matter of taste. I use let to emphasize a computation (by moving it to the front) and where to emphasize the program flow (by moving the computation to the back).

While there is the technical difference with respect to guards that ephemient pointed out, there is also a conceptual difference in whether you want to put the main formula upfront with extra variables defined below (where) or whether you want to define everything upfront and put the formula below (let). Each style has a different emphasis and you see both used in math papers, textbooks, etc. Generally, variables that are sufficiently unintuitive that the formula doesn't make sense without them should be defined above; variables that are intuitive due to context or their names should be defined below. For example, in ephemient's hasVowel example, the meaning of vowels is obvious and so it need not be defined above its usage (disregarding the fact that let wouldn't work due to the guard).

Legal:
main = print (1 + (let i = 10 in 2 * i + 1))
Not legal:
main = print (1 + (2 * i + 1 where i = 10))
Legal:
hasVowel [] = False
hasVowel (x:xs)
| x `elem` vowels = True
| otherwise = False
where vowels = "AEIOUaeiou"
Not legal: (unlike ML)
let vowels = "AEIOUaeiou"
in hasVowel = ...

Sadly, most of the answers here are too technical for a beginner.
LHYFGG has a relevant chapter on it -which you should read if you haven't already, but in essence:
where is just a syntactic construct (not a sugar) that are useful only at function definitions.
let ... in is an expression itself, thus you can use them wherever you can put an expression. Being an expression itself, it cannot be used for binding things for guards.
Lastly, you can use let in list comprehensions too:
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]
-- w: width
-- h: height
We include a let inside a list comprehension much like we would a predicate, only it doesn't filter the list, it only binds to names. The names defined in a let inside a list comprehension are visible to the output function (the part before the |) and all predicates and sections that come after of the binding. So we could make our function return only the BMIs of people >= 25:

I found this example from LYHFGG helpful:
ghci> 4 * (let a = 9 in a + 1) + 2
42
let is an expression so you can put a let anywhere(!) where expressions can go.
In other words, in the example above it is not possible to use where to simply replace let (without perhaps using some more verbose case expression combined with where).

Related

Using where in a list

Is there any way to use a where expression inside the list syntax? I imagined something like this would work:
foo = [i where i = 1]
But compilation yields:
error: parse error on input ‘where’
It's possible to use let ... in inside a list:
foo = [let i = 1 in i]
So I assume that where and let behave as different syntactic constructs?
I'm aware it's possible to do:
foo = [i] where i = 1
... but for more complicated lists the distance between the i and the i = 1 is too far for it to be clear - see the context section below and imagine many more test cases, and this testGroup itself nested inside a list.
Context
I ran across this while trying to write a readable testcase:
testGroup "toInput"
[
testProperty "toInput '*'" (forAll others conversionFails)
where others = arbitrary `suchThat` (\c -> c `notElem` exclChars)
conversionFails c = toInput c == Nothing
]
The equivalent with let just isn't as satisfying to read imo (and, more concretely, when surrounded by other test cases, the testProperty not being on the same indentation as them makes it harder to follow).
testGroup "toInput"
[
let others = arbitrary `suchThat` (\c -> c `notElem` exclChars)
conversionFails c = toInput c == Nothing
in
testProperty "toInput '*'" (forAll others conversionFails)
]
Like the Haskell Wiki article says:
It is important to know that let ... in ... is an expression, that is, it can be written wherever expressions are allowed. In contrast, where
is bound to a surrounding syntactic construct, like the pattern matching line of a function definition.
So in short, where is bound to the clause of a function declaration, whereas let is more locally scoped in an expression. If you write where, it is visible for the entire clause, like:
f a | a > 0 = g b b
| otherwise = b
where b = g a a
so here the where is visible for the two guards, a let is more locally scoped. If you write let y = f x in y * y, then that y is only visible in the in ... part. For example we can write:
Prelude> let a = 4 in (let a = 2 in a) + a
6
So here the inner a is 2 whereas the outer is 4. This might end up to be very confusing. If we would define variables with the same name in a where clause, this would result in name conflicts.
In case your code sample is a single function, you can of course move this out of the list definition, like:
foo exclChars =
testGroup "toInput" [testProperty "toInput '*'" (forAll others conversionFails)]
where others = arbitrary `suchThat` (`notElem` exclChars)
conversionFails = isNothing . toInput
[1 | 1==2] is a list comprehension too. 1==2 is a Boolean expression.
In your example foo = [let i = 1 in i], the let i = 1 in i is an expression as well.
Indeed where and let are different. let forms an expression, but where does not - it is a part of a definition (a = b where ...).
Difference is, a variable defined by where can be used in the definition's guards, whereas let goes on the right hand side of the = sign.
To your question, just move ] before the where, and it will become part of the definition where it appears.
You might be looking forward to using list comprehensions. In list comprehensions, you could use | which means such that, and you can say [ i | i <- [1] ]. So, you might use them as follows: [ ... | others <- [suchThat arbitrary (\c -> notElem c exclChars)] in your example.
I'm unsure about why do you want this specific list comprehension, but this works, and you can try it in GHCi:
> [ i | let i=1 ]
[1]
You can't instead use where in a list comprehension to this effect.

monadic desugaring haskell

Reading the chapter on monads in real world Haskell. I came across the desugaring of the do notation, specifically when we have something like pattern <- action.
-- file: ch14/Do.hs
doNotation3 =
do pattern <- act1
act2
{- ... etc. -}
actN
The above example is desugared into:
-- file: ch14/Do.hs
translated3 =
let f pattern = do act2
{- ... etc. -}
actN
f _ = fail "..."
in act1 >>= f
I am having trouble understanding is how you can have two pattern matching cases in a let clause?
I don't understand how you can have f pattern and f _ in the same let clause. I tried looking up if you can have multiple pattern matches in a let clause, but from what I have seen, most people use a case statement to do that.
I would like some help in understanding what is actually going on here?
I am having trouble understanding is how you can have two pattern matching cases in a let clause?
Well, you can:
example :: Int -> Int
example n =
let f 0 = 1
f x = x * f (x - 1)
in f n
Remember, that's a let … in… expression, not do's let. And for all bindings in such an expression, (almost) the same rules as for your usual top-level expressions hold, e.g. you can use pattern matching.
Maybe it gets a little bit easier if you transform it to where:
example :: Int -> Int
example n = f n
where
f 0 = 1
f x = x * f (x - 1)

Why Haskell disrespects bound identifiers for pattern matching?

f x zero = Nothing
f x y = Just $ x / y
where zero = 0
The literal-bound identifier zero simply matches all after the warning Pattern match(es) are overlapped.
That's how Haskell's syntax works; every lowercase-initial variable name in a pattern (re)binds that name. Any existing binding will be shadowed.
But even if that weren't the case, the binding for zero would not be visible to the first alternative, because of how Haskell's syntax works. A similar thing happens in the following version:
f = \v1 v2 -> case (v1, v2) of
(x, zero) -> Nothing
(x, y) -> Just $ x / y
where zero = 0
The where clause only applies to the one alternative that it's part of, not to the whole list of alternatives. That code is pretty much the same thing as
f = \v1 v2 -> case (v1, v2) of
(x, zero) -> Nothing
(x, y) -> let zero = 0 in Just $ x / y
If bound identifiers had different semantics than unbound identifiers in a pattern match, that could be quite error prone as binding a new identifier could mess up pattern matches anywhere that identifier is in scope.
For example let's say you're importing some module Foo (unqualified). And now the module Foo is changed to add the binding x = 42 for some reason. Now in your pattern match you'd suddenly be comparing the first argument against 42 rather than binding it to x. That's a pretty hard to find bug.
So to avoid this kind of scenario, identifier patterns have the same semantics regardless of whether they're already bound somewhere.
Because they are very fragile. What does this compute?
f x y z = 2*x + 3*y + z
Would you expect this to be equal to
f x 3 z = 2*x + 9 + z
f _ _ _ = error "non-exhaustive patterns!"
only because there's a y = 3 defined somewhere in the same 1000+ line module?
Also consider this:
import SomeLibrary
f x y z = 2*x + 3*y + z
What if in a future release SomeLibrary defines y? We don't want that to suddenly stop working.
Finally, what if there is no Eq instance for y?
y :: a -> a
y = id
f :: a -> (a -> a) -> a
f x y = y x
f x w = w (w x)
Sure, it is a contrived example, but there's no way the runtime can compare the input function to check whether it is equal to y or not.
To disambiguate this, some new languages like Swift uses two different syntaxes. E.g. (pseudo-code)
switch someValue {
case .a(x) : ... // compare by equality using the outer x
case .b(let x) : ... // redefine x as a new local variable, shadowing the outer one
}
zero is just a variable that occurs inside a pattern, just like y does in the second line. There is no difference between the two. When a variable that occurs inside a pattern, this introduces a new variable. If there was a binding for that variable already, the new variable shadows the old one.
So you cannot use an already bound variable inside a pattern. Instead, you should do something like that:
f x y | y == zero = Nothing
where zero = 0
f x y = Just $ x / y
Notice that I also moved the where clause to bring it in scope for the first line.

Why `where` produces a parse error inside list comprehension, but `let` doesn't?

Let's define a simple function called func:
func :: [Int] -> [Int]
I would like to use a where clause inside a list comprehension when defining this bogus function.
func xs = [ y where y = x + 1 | x <- xs]
Unfortunately, while trying to compile I get the following message:
parse error on input `where'
If I decide to use the let clause, everything works just fine:
func xs = [ let y = x + 1 in x | x <- xs] -- compilation successful
Why can't I use where like I originally intended to?
As you can see in the Haskell Report (https://www.haskell.org/onlinereport/exps.html#list-comprehensions) list comprehensions take an expression in the left hand side. let is an expression, whereas where is part of top level declarations. Hence, it's not allowed there.
This is because List comprehensions are equivalent to do-syntax.
To be clear, this:
[f a b q | a <- as, b <- bs, let q = a + b]
Is equivalent to:
do a <- as
b <- bs
let q = a + b
return (f a b q)
And let expressions are permitted in do-blocks.
As for why where clauses aren't permitted, they're intended to provide a temporary scope in a top-level declaration.
Ie:
binding = la da fu gu
where la a b c = c a b
da = 6
...
In other words, where is only permitted after a variable has been described, and therefore is not correct in list comprehensions.

Is it better to use guards than patterns for recursion functions in Haskell?

I'm just wondering about a recursion function I'm laying out in Haskell. Is it generally better to use guards than patterns for recursion functions?
I'm just not sure on what the best layout is but I do know that patterns are better when defining functions such as this:
units :: Int -> String
units 0 = "zero"
units 1 = "one"
is much preferred to
units n
| n == 0 = "zero"
| n == 1 = "one"
I'm just not sure though when it comes to recursion as to whether this is the same or different.
Just not quite sure on terminology: I'm using something like this:
f y [] = []
f y (x:xs)
| y == 0 = ......
| otherwise = ......
or would this be better?
f y [] = []
f 0 (x:xs) =
f y (x:xs) =
My general rule of thumb would be this:
Use pattern matching when the guard would be a simple == check.
With recursion, you usually are checking for a base case. So if your base case is a simple == check, then use pattern matching.
So I'd generally do this:
map f [] = []
map f (x:xs) = f x : map f xs
Instead of this (null simply checks if a list is empty. It's basically == []):
map f xs | null xs = []
| otherwise = f (head xs) : map f (tail xs)
Pattern matching is meant to make your life easier, imho, so in the end you should do what makes sense to you. If you work with a group, then do what makes sense to the group.
[update]
For your particular case, I'd do something like this:
f _ [] = []
f 0 _ = ...
f y (x:xs) = ...
Pattern matches, like guards, fall from top to bottom, stopping at the first definition that matches the input. I used the underscore symbol to indicate that for the first pattern match, I didn't care what the y argument was, and for the second pattern match, I didn't care what the list argument was (although, if you do use the list in that computation, then you should not use the underscore). Since it's still fairly simple ==-like checks, I'd personally stick with pattern matching.
But I think it's a matter of personal preference; your code is perfectly readable and correct as it is. If I'm not mistaken, when the code is compiled, both guards and pattern matches get turned into case statements in the end.
A simple rule
If you are recursing on a data structure, use pattern matching
If your recursive condition is more complex, use guards.
Discussion
Fundamentally, it depends on the test you wish to do to guard the recursion. If it is a test on the structure of a data type, use pattern matching, as it will be more efficient than redundant testing for equality.
For your example, pattern matching on the integers is obviously cleaner and more efficient:
units 0 = "zero"
units 1 = "one"
The same goes for recursive calls on any data type, where you distinguish cases via the shape of the data.
Now, if you had more complicated logical conditions, then guards would make sense.
There aren't really hard and fast rules on this, which is why the answers you've gotten were a bit hazy. Some decisions are easy, like pattern matching on [] instead of guarding with f xs | null xs = ... or, heaven forbid, f xs | length xs == 0 = ... which is terrible in multiple ways. But when there's no compelling practical issue, just use whichever makes the code clearer.
As an example, consider these functions (that aren't really doing anything useful, just serving as illustrations):
f1 _ [] = []
f1 0 (x:xs) = [[x], xs]
f1 y (x:xs) = [x] : f1 (y - 1) xs
f2 _ [] = []
f2 y (x:xs) | y == 0 = calc 1 : f2 (- x) xs
| otherwise = calc (1 / y) : f2 (y * x) xs
where calc z = x * ...
In f1, the separate patterns emphasize that the recursion has two base cases. In f2, the guards emphasize that 0 is merely a special case for some calculations (most of which are done by calc, defined in a where clause shared by both branches of the guard) and doesn't change the structure of the computation.
#Dan is correct: it's basically a matter of personal preferences and doesn't affect the generated code. This module:
module Test where
units :: Int -> String
units 0 = "zero"
units 1 = "one"
unitGuarded :: Int -> String
unitGuarded n
| n == 0 = "zero"
| n == 1 = "one"
produced the following core:
Test.units =
\ (ds_dkU :: GHC.Types.Int) ->
case ds_dkU of _ { GHC.Types.I# ds1_dkV ->
case ds1_dkV of _ {
__DEFAULT -> Test.units3;
0 -> Test.unitGuarded2;
1 -> Test.unitGuarded1
}
}
Test.unitGuarded =
\ (n_abw :: GHC.Types.Int) ->
case n_abw of _ { GHC.Types.I# x_ald ->
case x_ald of _ {
__DEFAULT -> Test.unitGuarded3;
0 -> Test.unitGuarded2;
1 -> Test.unitGuarded1
}
}
Exactly the same, except for the different default case, which in both instances is a pattern match error. GHC even commoned-up the strings for the matched cases.
The answers so far do not mention the advantage of pattern matching which is the most important for me: ability to safely implement total functions.
When doing pattern matching you can safely access the internal structure of the object without the fear of this object being something else. In case you forget some of the patterns, the compiler can warn you (unfortunately this warning is off by default in GHC).
For example, when writing this:
map f xs | null xs = []
| otherwise = f (head xs) : map f (tail xs)
You are forced to use non-total functions head and tail, thus risking the life of your program. If you make a mistake in guard conditions, the compiler can't help you.
On the other hand, if you make an error with pattern matching, the compiler can give you an error or a warning depending on how bad your error was.
Some examples:
-- compiles, crashes in runtime
map f xs | not (null xs) = []
| otherwise = f (head xs) : map f (tail xs)
-- does not have any way to compile
map f (h:t) = []
map f [] = f h : map f t
-- does not give any warnings
map f xs = f (head xs) : map f (tail xs)
-- can give a warning of non-exhaustive pattern match
map f (h:t) = f h : map f t

Resources