In Haskell, what is the difference between using and not using let? - haskell

Someone told me Haskell does not have variables but bindings. Now what ever that means, I always wondered what the difference is when writing these bindings, like so:
x = 5
and
let x = 5
What is the difference here?
And a followup question: Am I even creating variables by doing this? If x is not a variable, what is it?

The only real difference is where they occur.
-- At top (file) level or in "where" blocks, omit "let".
x = 5
f1 y = x + y
where
x = 5
-- Inside expressions or do-blocks, "let" is required.
f2 y = let x = 5
in x + y
f3 y = do someAction
let x = 5
return (x + y)
In all cases, x is a variable. However, you cannot change (mutate) the value of the variable.
In the GHCi prompt, it seems like you change the value of a variable, but you cannot. You can only create new variables with the same name, the old variables still exist.
Prelude> let x = 3
Prelude> let f y = x + y
Prelude> let x = 10
Prelude> f 1
4
If you had really changed the value of x, then f 1 would be 11.

Haskell has variables, but we say they are bound rather than assigned. These are extremely similar notions, but they differ in whether they support multiple assignment - Haskell does not.
do let x = 1
let x = 2
print x -- prints "2"
When we say it does not, what we mean is that all variables are bound statically. This means that any time there's a reference to a variable, you can look back up through the code and find the one binding that it refers to.
Take, for example, Python, which does have multiple assignment.
def f(a):
x = 1 # first assignment
x = 2 # second assignment
for i in a:
x = i # third assignment
print x
print x
In the above example, there are three places where x is assigned. When we refer to x on the last line, we could be getting the 2 from the second assignment, or we could be getting one of the values from a from the assignment in the loop. Whether the third assignment took place depends on whether a was empty or not.
So let's look at similar code in Haskell:
f a = do let x = 1 -- first binding
let x = 2 -- second binding
for_ a $ \i -> do let x = i -- third binding
print x
print x
The final line of this output will always be "2", because at that point in the code, the second binding is the innermost binding that x received in that scope. If we were to introduce another closer binding, then we could change that:
f a = do let x = 1 -- first binding
let x = 2 -- second binding
for_ a $ \i -> do let x = i -- third binding
print x
let x = head a -- fourth binding
print x
But what we can never do is introduce ambiguity about which binding something refers to.

Related

How `fix f = let {x = f x} in x` is evaluated?

fix f = let {x = f x} in x
Talking about let, I thought that let P = Q in R would evaluate Q -> Q' then P is replaced by Q' in R, or: R[P -> Q'].
But in fix definition the Q depends on R, how to evaluate then?
I imagine that this is about lazy evaluation. Q' becomes a thunk, but I can't reason this in my head.
As a matter of context, I'm looking at Y combinator, it should find a fixed point of a function so if I have this function, one x = 1, then fix one == 1 must hold, right?
So fix one = let {x = one x} in x, but I can't see how 1 would emerge from that.
Talking about let, I thought that let P = Q in R would evaluate Q -> Q' then P is replaced by Q' in R, or: R[P -> Q'].
Morally, yes, but P is not immediately evaluated, it is evaluated when needed.
But in fix definition the Q depends on R, how to evaluate then?
Q does not depend on R, it depends on P. This makes P depend on itself, recursively. This can lead to several different outcomes. Roughly put:
If Q can not return any part of its result before evaluating P, then P represents an infinitely recursing computation, which does not terminate. For example,
let x = x + 1 in x -- loops forever with no result
-- (GHC is able to catch this specific case and raise an exception instead,
-- but it's an irrelevant detail)
If Q can instead return a part of its result before needing to evaluate P, it does so.
let x = 2 : x in x
-- x = 2 : .... can be generated immediately
-- This results in the infinite list 2:2:2:2:2:.....
let x = (32, 10 + fst x) in x
-- x = (32, ...) can be generated immediately
-- hence x = (32, 10 + fst (32, ...)) = (32, 10+32) = (32, 42)
I imagine that this is about lazy evaluation. Q' becomes a thunk, but I can't reason this in my head.
P is associated with a thunk. What matters is whether this thunk calls itself before returning some part of the output or not.
As a matter of context, I'm looking at Y combinator, it should find a fixed point of a function so if I have this function. one x = 1, then fix one == 1 must hold, right?
Yes.
So fix one = let x = one x in x, but I can't see why 1 would emerge from that
We can compute it like this:
fix one
= {- definition of fix -}
let x = one x in x
= {- definition of x -}
let x = one x in one x
= {- definition of one -}
let x = one x in 1
= {- x is now irrelevant -}
1
Just expand the definitions. Keep recursive definitions around in case you need them again.

Creating a new function inside a function based on the parameters of the first

So I have a function that returns a function. The returned function is supposed to return 0 for all inputs except x. For x it should return 10.
g x = do
let
f x = 10
f _ = 0
f
But instead the function always returns 10:
(g 3) 4
10
It seems that the parameter x is no the same x that gets used to create the function f. So how can I achieve that?
Your approach seems to be trying to use pattern matching like it's unification - Haskell doesn't perform unification, and pattern matching only works for things like data constructors (eg. Just), not for values.
The name x you're using in the inner definition shadows the name x used in the outer definition - so your inner function is equivalent to:
f x = 10
You should use a different variable name, and make your inner function compare its argument to the outer function's argument:
g x = let f y = if x == y then 10 else 0
in f
Or using currying, which is arguably better style:
g x y = if x == y then 10 else 0
This is semantically equivalent to the above version, and is also semantically equivalent to a function returning a lambda. We can partially apply g to a value to produce a function taking one parameter, eg:
> (g 3) 4
0
> (g "hi") "hi"
10
Pattern-matching "f X" compares argument with X only if X is a literal or data constructor (like "True"). When X is a variable it binds a new variable - in this case another "x" which shadows the outer one. You have to use good old comparison. For example, with guards:
f y | x == y = ...
f _ = ...
Haskell does not allow unification of variables that share the same name.
For example, f x x = ... is a syntax error rather than to say "match this case when the first and the second arguments are equal".
In your case, you have the same conceptual problem but no syntax error because Haskell simply shadows x from g once you try to match it using an argument in f. As matching a variable x without a constructor is unconditional it always succeeds and returns 10.
You want a function like this:
g x = \y -> if x == y then 10 else 0
which uses the (==) operator explicitly.

What is a = a doing in haskell? [duplicate]

I was learning some new Haskell today, when I tried something in ghci.
It basically boiled down to this:
Prelude> let x = 6
Prelude> x
6
Prelude> let y = show x
Prelude> y
"6"
Prelude> let x = show x
Prelude> x
"\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" --(repeats)
So can ghci not self-reference in assignment? I feel like it's akin to i = i++; in C, or trying to reference previous assignments of a let (not let*) in Scheme. Is there anyway to do this, or should I just use the easier let y = show x?
Definitions in Haskell are recursive by default. So the definition you made for x refers to the very same x, which is the reason for the very long string you are seeing, because x is defined to a String that is the result of calling show on itself, so you keep seeing the opening quotes for showing a string, and then those opening quotes escaped, and so on.
These kinds of definitions can be surprisingly useful. For example if you write:
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
you can define the Fibonacci sequence in terms of itself as an infinite list.
Then you can do something like take 10 fibs to just see the first 10 elements.
It's self referencing indeed! It's trying to solve the equation
x = show x
Since show returns a string Haskell knows that x begins like "\"" and that's enough to guess the second character, which is enough for the third which is enough for the fourth...
And so on.
Yes, you can do a not-selfreferencing assignment in ghci, although it's a bit cumbersome:
let x = 5
x <- return $ show x
lets are recursive, while monadic bindings are not.
Again: yes, Haskell very much can self-reference in assignment, otherwise this would just give an error instead of printing something undecipherable, wouldn't it?
What you can not do in Haskell, ever, is modify / re-assign the value of a variable. It's just totally out of question: if you've once defined x as some value, x will keep this value forever. An assumption baked into the very language, and used to great avail by the compiler for lots of optimisations etc..
Now you wonder why you can write let x = ... again at all, didn't I just say this is not possible? The thing is, what you're doing there is define a new variable that also happens to have the name x, but that doesn't change anything about the old variable with the same name. You might expect this
Prelude> let x = 6
Prelude> let p = print x
Prelude> let x = 7
Prelude> p
to yield 7, but actually it prints 6 because p is still referring to the old variable x, not to the new one that was defined only later.
Still confused? Perhaps less strange is something like
n :: Int
n = 7
f :: IO ()
f = print $ replicate n "ha"
... -- much later, you've forgotten there was a global `n` up there...
g :: String -> String
g = take n
where n = 37
It's quite reasonable that f will take 37 characters, not 7, while any call to f continues to repeat the string only 7 times. After all, it's "g, where n has that value", but nothing else outside. Now, let is just where written the other way around. In particular, a do notation or your GHCi prompt is actually syntactic sugar for something like this:
let x = 6
in ( print x >> ( let y = show x
in ( print y >> ( let x = show x
in ( print x )
)
)
)
Each paren encloses a scope. Variables defined in outer scopes can be used, but local ones are preferred if found. So let x = show x in ( print x ) can be considered completely on its own, the original x = 6 is shadowed out of scope here. Therefore, the only way the definition can work is refer recursively to itself.

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.

ghci self-referencing assignment

I was learning some new Haskell today, when I tried something in ghci.
It basically boiled down to this:
Prelude> let x = 6
Prelude> x
6
Prelude> let y = show x
Prelude> y
"6"
Prelude> let x = show x
Prelude> x
"\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" --(repeats)
So can ghci not self-reference in assignment? I feel like it's akin to i = i++; in C, or trying to reference previous assignments of a let (not let*) in Scheme. Is there anyway to do this, or should I just use the easier let y = show x?
Definitions in Haskell are recursive by default. So the definition you made for x refers to the very same x, which is the reason for the very long string you are seeing, because x is defined to a String that is the result of calling show on itself, so you keep seeing the opening quotes for showing a string, and then those opening quotes escaped, and so on.
These kinds of definitions can be surprisingly useful. For example if you write:
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
you can define the Fibonacci sequence in terms of itself as an infinite list.
Then you can do something like take 10 fibs to just see the first 10 elements.
It's self referencing indeed! It's trying to solve the equation
x = show x
Since show returns a string Haskell knows that x begins like "\"" and that's enough to guess the second character, which is enough for the third which is enough for the fourth...
And so on.
Yes, you can do a not-selfreferencing assignment in ghci, although it's a bit cumbersome:
let x = 5
x <- return $ show x
lets are recursive, while monadic bindings are not.
Again: yes, Haskell very much can self-reference in assignment, otherwise this would just give an error instead of printing something undecipherable, wouldn't it?
What you can not do in Haskell, ever, is modify / re-assign the value of a variable. It's just totally out of question: if you've once defined x as some value, x will keep this value forever. An assumption baked into the very language, and used to great avail by the compiler for lots of optimisations etc..
Now you wonder why you can write let x = ... again at all, didn't I just say this is not possible? The thing is, what you're doing there is define a new variable that also happens to have the name x, but that doesn't change anything about the old variable with the same name. You might expect this
Prelude> let x = 6
Prelude> let p = print x
Prelude> let x = 7
Prelude> p
to yield 7, but actually it prints 6 because p is still referring to the old variable x, not to the new one that was defined only later.
Still confused? Perhaps less strange is something like
n :: Int
n = 7
f :: IO ()
f = print $ replicate n "ha"
... -- much later, you've forgotten there was a global `n` up there...
g :: String -> String
g = take n
where n = 37
It's quite reasonable that f will take 37 characters, not 7, while any call to f continues to repeat the string only 7 times. After all, it's "g, where n has that value", but nothing else outside. Now, let is just where written the other way around. In particular, a do notation or your GHCi prompt is actually syntactic sugar for something like this:
let x = 6
in ( print x >> ( let y = show x
in ( print y >> ( let x = show x
in ( print x )
)
)
)
Each paren encloses a scope. Variables defined in outer scopes can be used, but local ones are preferred if found. So let x = show x in ( print x ) can be considered completely on its own, the original x = 6 is shadowed out of scope here. Therefore, the only way the definition can work is refer recursively to itself.

Resources