2

I'm pretty new to Haskell, so any help is appreciated!

I'm using an IOArray to update random elements in constant space. I have a wrapper that looks like this:

data W = W{ arr:: IO (IOArray Int Node), n :: Int, ... }

However, I can't find a way to update arr so that it's visible when the wrapper is being passed around without doing something like wrappper{arr = x}, which wastes a lot of GC time. In tests, it turns out to be too slow.

Is there any way to update arr so that it's globally visible? Thanks!

4
  • 3
    Mutable data in Haskell needs to be wrapped in a Monad, perhaps look to see if the ST monad isn't better suited for your needs Commented Nov 14, 2013 at 15:36
  • 3
    jozefg is right: there's also STArray, and note that runST can turn an ST action into a pure value. Commented Nov 14, 2013 at 15:37
  • data W s = W{ arr :: STArray s Int Node, ...}. Do I just have to create the array entirely before putting it in the wrapper? That could be a viable way of doing it Commented Nov 14, 2013 at 16:00
  • @Craig I've posted a quick example below Commented Nov 14, 2013 at 16:19

1 Answer 1

3

Here's a quick example of how to use ST arrays

import Data.Array.ST hiding (unsafeThaw) -- Deprecated
import Data.Array (Array)
import Data.Array.Unsafe (unsafeThaw) -- If you really really really need it

newtype W a = W {arr :: Array Integer a}

modifyW :: a -> W a -> W a
modifyW v (W arr) = W $ runSTArray $ do -- The double $ is on purpose, . doesn't
                                        -- play so well with Rank n types.
  a <- thaw arr -- Turn `arr` into something we can modify
  writeArray a 1 v -- modify it
  return a

This will ensure the computation is pure, but the array will not be copied inside modifyW, all those modifications are constant time. If you can't afford any copying at all you can use unsafeThaw. But this is well.. unsafe. It'll actually modify the pure array so you have to be extremely careful not to try to use the pure structure after modifyW is run. This is much harder than it sounds thanks to lazy evaluation so I'd caution you against this.

With this style, you read from the pure Array, then when you need to modify it, you run in the ST monad which let's you do impure things, but won't let them bleed into the rest of your program.

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

4 Comments

That is amazing! I'll try my best to avoid these unsafe features down the road, but they're definitely a good way to get off the ground!
@Craig Don't go overboard :) Generally when you find yourself reaching for unsafe* you're doing something wrong. But yes, occasionally they are invaluable
@Craig "but they're definitely a good way to get off the ground!" I'd like to give a more forceful "no way!" response to this; I think unsafe* functions should be thought of as a (dangerously) accessible plugin interface to the internals of GHC. Strapping dynamite to your boots is also a good way to get off the ground :)
Yeah, it turns out that unsafe thaw doesn't play well with the optimizer, so I'll be doing this safely :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.