I am quite confused with the concept of immutable variables in Haskell. It seems like that we can't change the value of variables in Haskell. But when I tried following code in GHCI, it seemed like the value of variables did change:
Prelude> foo x=x+1
Prelude> a=1
Prelude> a
1
Prelude> foo a
2
Prelude> a=2
Prelude> a
2
Prelude> foo a
3
Does this conflict with the idea of immutable variables?
Many thanks!
Such variables cannot change their value or state. Therefore, once we assign them the value during declaration we cannot make changes in the future if a need arises. Moreover, if we try to change an immutable variable python gives an error.
Haskell "defaults to" immutable single-linked lists, but also supports both immutable and mutable arrays.
Haskell is a purely functional language, which means there are no side-effects and all variables are immutable.
So, YES Haskell has true variables. But it does not use mutable variables by default.
Haskell doesn't allow you to modify existing variables. It does, however, allow you to re-use variable names, and that's all that's happening here. One way to see this is to ask GHCi, using the :i[nfo]
directive, where the variable was declared:
Prelude> let a = 1
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:2:5
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
These are actually two entire seperate, different variables, which just happen to be called the same name! If you just ask for a
, the newer definition will be “preferred”, but the old one is still there – one way to see this, as remarked by chi in the comments, is to use a
in a function:
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
Prelude> let f x = a + x
Prelude> let a = 3
Prelude> f (-2)
0
f
never needs to care that you've defined a new variable that's also called a
; from its perspective a
was one immutable variable that always stays as it is.
It's worth talking a bit about why GHCi prefers the later definition. This does not otherwise happen in Haskell code; in particular if you try to compile the following module, it simply gives an error concerning duplicate definition:
a = 1
a = 2
main :: IO ()
main = print a
The reason that something like this is allowed in GHCi is that it works different from Haskell modules. The sequence of GHCi commands forms in fact a sequence of actions in the IO monad†; i.e. the program would have to be
main :: IO ()
main = do
let a = 1
let a = 2
print a
Now, if you've learned about monads you'll know that this is just syntactic sugar for
main =
let a = 1 in (let a = 2 in (print a))
and this is really the crucial bit for why you can re-use the name a
: the second one, a = 2
, lives in a narrower scope than the first. So it is more local, and local definitions have priority. Whether this is a good idea is a bit debatable; a good argument for it is that you can have a function like
greet :: String -> IO ()
greet name = putStrLn $ "Hello, "++name++"!"
and it won't stop working just because somebody defines elsewhere
name :: Car -> String
name car | rollsOverAtRightTurn car = "Reliant Robin"
| fuelConsumption car > 50*litrePer100km
= "Hummer"
| ... = ...
Besides, it's really quite useful that you can “redefine” variables while fooling around in GHCi, even though it's not such a good idea to redefine stuff in a proper program, which is supposed to show consistent behaviour.
†As dfeuer remarks, this is not the whole truth. You can do some things in GHCi that aren't allowed in an IO
do-block, in particular you can define data
types and class
es. But any normal statement or variable definition act as it were in the IO
monad.
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