2012-04-09 18 views
2

私は並列計算を行い、結果をSTArrayに書き込もうとしています。私はこのコードが私がやろうとしていることを示していると思います。しかし、コンパイルエラーが発生しています。STArrayを使ったHaskell並列計算

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 

どうすればよいですか?

+0

パラレルアレイの操作に[Repa](http://hackage.haskell.org/package/repa)を使うべきだと思います。 – leftaroundabout

答えて

9

newArrayを使用します。ただし、main関数の本体で使用すると、doのすべてがIOタイプである必要があります。 STIOではないため、タイプは一致しません。

最初に、newArraySTモナドにアクセスできるコンテキストに移動する必要があります。このコンテキストはrunSTArrayの体内で利用できるのは勿論であるので、身体への変更:次に、あなたはどのように振る舞うparを再考する必要が

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 

parは、の純粋な計算を行うためのものであり、モナドアクションには使用できません。モナドは、一般に並列化することはできません。特に、STのモナドは、並列計算のための代替手段を提供していません。配列への並列書き込みは競合状態に繋がる可能性があります(同じセルを上書きするとどうなりますか?どの書き込みがカウントされ、どちらがどちらにならないか)、ここでは並列性を許可するのは危険です。

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 

ただし、書き込みは高価ではありません。それは高価かもしれない値の計算です。例えば、1723をオンザフライで計算したいとします。

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 

私はSTArray sがあるとは思わない:あなたはこのようにそれを保存する必要がありますので、あなたは、runSTArrayは、結果の配列を返すことを認識しなければならない、最後に

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

:あなたは、次の操作を行うことができますここには正しい解決策があります。並列対称配列計算が必要な状況では、repaのようなより強力な配列ライブラリを使用する必要があります。

+0

ありがとう、私はシーケンシャルな読み書き方法を理解していました。あなたが指摘しているように、パーモードは私にこれらのアクションをパラレル化させることができないので、私は立ち往生したようです。私はRepaを使って配列に並列書き込みを行う方法を調べなければなりません。 – Kevin

+0

並列処理を行なわないSTのモナドです。あなたが好きなのであれば、 'forkIO'と会社で' IO'でそれをすることができます。 –

+0

@LouisWasserman詳しいことはありますか?これは私がすべてのフォークされたスレッドから同じ配列に書き込むことができますか? – Kevin

1

parは、純粋な演算を並列に構成するためのものです。効果的な操作を構成しています。あなたはパーを使うことはできません。さらに、並列性は、少なくとも(突然変異で構成された場合は)であり、STモナドでは利用できません。私はあなたのコードを構造化する正しい方法について助言することはできません。実際の問題のドメインが何であるかを知るにはあまりにも細かいことがあるからです。しかし私の一般的なアドバイスは、fork(IOモナドの中の)またはのような明示的な並行性の構造を使用して、mutatey配列ではなく純粋な操作を使用することです。