hallamsamuel
hallamsamuel

Reputation: 1

Modify a list in haskell

I have a list of chars

left = ['h', 'e', 'l', 'l', 'o']

and the function

typer :: [Char] -> Char -> [Char]
typer left c = left ++ [c]

Which seems to work if I type typer left 'a' into ghci it returns "helloa" but if I then try to read left it returns "hello". Where does the "a" go? is there anyway to manipulate left using the function?

example of console output

Upvotes: 0

Views: 1499

Answers (3)

C. L. M. Petersson
C. L. M. Petersson

Reputation: 1

Not usually, no. Usually, Haskell variables are not mutable. There are however libraries that contain mutable variables. For example, Data.IORef contains IORef, which is mutable. I will explain how to use them below, but as a general rule, using I would recommend against it, and instead write your code in a more functional manner.

With IORef, your function typer can be rewritten

typer :: IORef [Char] -> Char -> IO()
typer left c = writeIORef left . (++[c]) =<< readIORef left

Let us consider its different parts.

  • readIORef left pulls out the value "hello" from the IORef and wraps it in the IO monad.
  • f =<< x takes x, which is wrapped in a monad, unwraps it and passes it as an argument to f, but only if we promise that f returns a value wrapped in the same monad. Here, x is "hello" wrapped in IO and f is writeIORef left . (++[c]).
  • . combines the functions writeIORef left and (++[c]) into one, so that (++[c]) is applied before writeIORef left.
  • (++[c]) appends the character c.
  • writeIORef left returns an empty action wrapped in IO (IO()), but it has the side effect that the value of the IORef left is modified. Since it returns a value wrapped in IO, the promise we made to =<< is fulfilled.

With the above function, the code

main :: IO()
main = do x <- newIORef "hello"
          typer x 'a'
          readIORef x >>= print

should yield the desired effect.

Upvotes: 0

Steven Armstrong
Steven Armstrong

Reputation: 475

Nope! Values in Haskell are immutable.

You have declared your left to be equal to "hello", and it will always be equal to "hello". You can hide that particular left value with some new token called left in a closer scope (such as having a function argument called left, which will make the globally defined left invisible in the function body). There is however no way to change your declared left value[1].

A new string is returned by typer, and you have to hold onto that value if you want to hold onto "helloa".

[1] In GHCi, you can hide previous definitions by re-defining them. This quietly re-purposes the existing name to point to a new value. You cannot do this in a Haskell source file.

Upvotes: 2

Wyzard
Wyzard

Reputation: 34581

Haskell functions are pure functions, which means they can't have side effects such as modifying variables. Your typer function computes a result based on its arguments, but it doesn't (and can't) actually modify its arguments.

As an analogy, in mathematics, if n is 4 then sqrt(n) is 2, but n is still 4 even after you've computed its square root.

If you want to capture the result of your function call so you can use it later, assign it to another variable:

right = typer left 'a'

Upvotes: 3

Related Questions