Frage

I'm trying to do computation in parallel, and write the results to an STArray. I think this code shows what I'm trying to do. However, I'm getting compile errors.

import Control.Monad
import Control.Monad.ST
import Control.Parallel
import Data.Array.ST

main = do
    arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
    runSTArray $ do
        par (writeArray arr (1,1) 17) (writeArray arr (2,2) 23)
        return arr
    print arr

How should I do this?

War es hilfreich?

Lösung

You use newArray, which has the type ST s (STArray s (Int, Int) Int). However, you use it in the body of the main function, which means that everything you do must have an IO type. ST is not IO, so the types cannot match.

You should first move the newArray into a context where you have access to the ST monad. This context is of course available in the body of runSTArray, so change the body to:

    runSTArray $ do
        arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
        par (writeArray arr (1,1) 17) (writeArray arr (2,2) 23)
        return arr

Then, you need to rethink how par behaves. par is for creating parallel pure computations, and cannot be used for monadic actions; monads cannot generally be parallelized at all. In particular, the ST monad doesn't even offer any alternatives for parallel computations; since parallel writes to an array can lead to race conditions (what happens if you overwrite the same cell? Which write will count, and which one won't?), it is unsafe to allow parallelism here. You must change the array in sequence:

    runSTArray $ do
        arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
        writeArray arr (1,1) 17
        writeArray arr (2,2) 23
        return arr

However, the writes aren't expensive; it's the calculations of the values that might be expensive. Suppose that you want to calculate 17 and 23 on the fly; you can then do the following:

let a = someLongCalculation 12534
    b = a `par` (someLongCalculation 24889)
writeArray arr (1, 1) a
writeArray arr (2, 2) b

Finally, you must realize that runSTArray returns the result array, so you must store it like this:

import Control.Monad
import Control.Monad.ST
import Control.Parallel
import Data.Array.ST

main =
  let pureArr =
        runSTArray $ do
          arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
          writeArray arr (1,1) 17
          writeArray arr (2,2) 23
          return arr
  in print pureArr

I don't think that STArrays are the correct solution here. You should use a more powerful array library like repa in situations where you need parallel symmetrical array computations.

Andere Tipps

par is for composing pure operations in parallel. you're composing effectful operations. you can't use par. Furthermore, parallelism is an effect (at least when composed with mutation), and isn't available to you in the ST monad. I can't give you advice on the right way to structure your code, because things are too cut down to see what you're actual problem domain is. My general advice, however, is, to use explicit concurrency constructs like fork (in the IO monad) or to use pure operations rather that mutatey arrays.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top