Haskell does not allow changing existing variables. However, it does allow you to reuse variable names and everything that happens here. One way to see this is to ask GHCi using the directive :i[nfo] where the variable was declared:
Prelude> let a = 1 Prelude> :ia a :: Num a => a -- Defined at <interactive>:2:5 Prelude> let a = 2 Prelude> :ia a :: Num a => a -- Defined at <interactive>:4:5
In fact, these are two whole separate variables that are simply called the same name! If you just ask a , a newer definition will be "preferred", but the old one still exists; one way to see this, as qi noted in the comments, is to use a in a function:
Prelude> let a = 2 Prelude> :ia a :: Num a => a -- Defined at <interactive>:4:5 Prelude> let fx = a + x Prelude> let a = 3 Prelude> f (-2) 0
f never have to make sure that you define a new variable, also called a ; from his point of view, a was one immutable variable, which always remains as it is.
It's worth a little talk about why GHCi prefers a later definition. This does not mean in Haskell code; in particular, if you try to compile the following module, it just gives an error regarding the duplicate definition:
a = 1 a = 2 main :: IO () main = print a
The reason that something similar is allowed in GHCi is because it is different from Haskell modules. The sequence of commands GHCi actually forms a sequence of actions in the IO monad & dagger; ; that is, the program should be
main :: IO () main = do let a = 1 let a = 2 print a
Now, if you learn about monads, you’ll find out that this is just syntactic sugar for
main = let a = 1 in (let a = 2 in (print a))
and this is a really important bit for why you can reuse the name a : the second, a = 2 , lives in a narrower area than the first. Therefore, it is more local, and local definitions take precedence. Whether this is a good idea is a bit controversial; a good argument that you can have a function like
greet :: String -> IO () greet name = putStrLn $ "Hello, "++name++"!"
and it won’t stop working just because someone determines elsewhere
name :: Car -> String name car | rollsOverAtRightTurn car = "Reliant Robin" | fuelConsumption car > 50*litrePer100km = "Hummer" | ... = ...
It’s also very useful that you can “redefine” variables by tricking yourself into GHCi, although it is not such a good idea to redefine material in the right program, which should show consistent behavior.
& dagger; As dfeuer notes, this is not the whole truth. You can do some things in GHCi that are not allowed in the do IO block, in particular you can define data and class es types. But any normal expression or definition of a variable acts as if in an IO monad.