user5846939
user5846939

Reputation: 427

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

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?

Upvotes: 9

Views: 859

Answers (2)

Chris Martin
Chris Martin

Reputation: 30736

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.

Upvotes: 6

Dietrich Epp
Dietrich Epp

Reputation: 213228

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.

Upvotes: 15

Related Questions