Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does immutable variable in Haskell mean?

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!

like image 795
yxw Avatar asked Jun 26 '16 16:06

yxw


People also ask

What does it mean for a variable to be immutable?

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.

Are Haskell lists immutable?

Haskell "defaults to" immutable single-linked lists, but also supports both immutable and mutable arrays.

Is Haskell mutable?

Haskell is a purely functional language, which means there are no side-effects and all variables are immutable.

Are there variables in Haskell?

So, YES Haskell has true variables. But it does not use mutable variables by default.


1 Answers

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 classes. But any normal statement or variable definition act as it were in the IO monad.

like image 50
leftaroundabout Avatar answered Oct 15 '22 20:10

leftaroundabout