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?
In Haskell let, binding is used to bind the variables, which are very local. In Haskell, we can define any type of variable using let keyword before the variable name in Haskell. But their scope is local, we also have let in Haskell which is another form of defining the variable and use them after it.
() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .
You can't. Once a variable has a value, it has that value forever.
It represents "computations that could fail to return a value". Just like with the fmap example, this lets you do a whole bunch of computations without having to explicitly check for errors after each step.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With