2

I would like to have an array, say:

myArray = [1,2,3,4,5,6,7,8,9]

and be able to run a function that changes a value in the list to another value. I would like to be able to run this function several times with myArray updating to the new set of numbers after each run.

myArray = [1,2,3,4,5,6,7,8,9]
>>> f 1 5 myAarray 
>>> myArray
[1,2,3,4,1,6,7,8,9]
>>> f 3 8 myArray
>>> myArray
[1,2,3,4,1,6,7,3,9]

How do I create a holder for my values that can have changing values.

Thanks!

9
  • 2
    You can't have mutable values in Haskell. Maybe you want to look into Monads? Commented Dec 14, 2015 at 15:08
  • 3
    Mutable values are this way -----> click here Commented Dec 14, 2015 at 15:22
  • 5
    @n.m. thanks and congrats on the most unhelpful comment I have come across yet! Commented Dec 14, 2015 at 15:39
  • 1
    You are welcome. Answers are supposed to be helpful, comments can bee jokes and whatnot. Are you a Haskell beginner? Your question doesn't have an answer that is both helpful and beginner-friendly. Well if you think "don't do it" is a helpful answer, then here you go. Commented Dec 14, 2015 at 15:53
  • 3
    Storing mutable values is not by itself a problem that needs to be solved, it is a tool to solve other, real-world problems. Haskell is a powerful tool to solve real-world problems, built upon mostly immutable values. Immutability is essential for it to work. Haskell can have mutability too (IORef, State monad), but it's an advanced topic and it is very much advised to learn the basics before trying to deal with mutability. Commented Dec 14, 2015 at 16:06

1 Answer 1

4

All Haskell values are immutable. You can't change a value that's bound to a name (you can shadow them in GHCi, but that's a slightly different thing).

If you want to achieve true1 mutability, you need an immutable reference to mutable data. To use those, typically you'd want to be in a monadic context.

Here's an example using a rather low-level reference type called IORef:

import Data.IORef
import Control.Monad

f :: [Int] -> [Int]
f = map (+1)

main = do
    a <- newIORef [1,2,3,4,5]
    readIORef a >>= print
    readIORef a >>= (return . f) >>= writeIORef a
    readIORef a >>= print

Note that the value of a doesn't change; it still points to the same "value location". What changes is the actual value that's being pointed to.


That being said, this requires using the IO monad which is generally frowned upon. Depending on your needs, a fully pure solution like State might work better.

-- assume previous f
g :: State [Int] ()
g = modify f

Now you only need to start with some state, and the state monad will chain the modifications for you, like so:

main = print $ execState (g >> g >> g) [1,2,3,4,5]

This is essentially equivalent to simple composition:

f . f . f $ [1,2,3,4,5]

Which, last but not least, could be your default go-to solution in Haskell.


P.S. I'm using a simpler f in my examples, but there's no reason you couldn't do:

(f 1 5) . (f 3 8) $ myArray

1This is somewhat ambiguous, but for the sake of simplicity I'd expand this to "the one that could be backed by direct memory operations".

Sign up to request clarification or add additional context in comments.

3 Comments

thanks. This is helpful. The idea was to have a list that will track what set a certain item in an array belongs to. The f x y puts the item at y in the same set as x etc. So, am I correct in believing that the only pure way of doing it is to somehow chain my functions either directly or through State?
@matthias Pretty much yes. State is typically satisfactory though - there's a strict variant of it available, as well as the StateT transformer. Other methods either use IO directly or via some safer wrapper (ST and STM would be notable examples of such).
I don't think you can change bindings in GHCi either; if I'm not very much mistaken, you can only shadow them.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.