2014-02-20 75 views
2

我一直在研究如何在ST計算中創建和使用多個STUArrays。具體方案是:使用並返回多個STUArrays

  1. 創建多個磁盤陣列,但只返回他們中的一個
  2. 創建多個磁盤陣列,但回報沒有人
  3. 創建多個磁盤陣列,並返回多個陣列

我有答案到(1)和(2),但不是(3)。

首先是一些進口的,所以我們知道一切從何而來:

import Control.Monad.ST (ST,runST) 
import Data.Array.Base (unsafeFreezeSTUArray) 
import Data.Array.ST (STUArray) 
import Data.Array.Unboxed (UArray) 
import Data.STRef (STRef, newSTRef, readSTRef, writeSTRef) 
import Data.Array.MArray (getBounds, newArray, readArray, writeArray, newListArray) 
import Data.Array.ST (runSTUArray) 

對於(1),一個技巧就是定義一個新的數據類型和構造函數:

data ArrayPair s = AP (STUArray s Int Int) (STUArray s Int Bool) 

newAP n = do 
    a1 <- newArray (1,n) 0 
    a2 <- newArray (1,n) False 
    return $ AP a1 a2 

而這裏的如何返回其中一個陣列:

foo :: UArray Int Int 
foo = runSTUArray $ do 
     AP ints bools <- newAP 10 
     writeArray ints 1 42 
     writeArray bools 1 True 
     -- do stuff with ints and bools 
     return ints 

對於(2),您可以添加STRef的數據結構,結束與readSTRef計算和與runST運行:

data WorkState s = WS (STUArray s Int Int) 
         (STUArray s Int Bool) 
         (STRef s Char) 

newWS = do 
    ints <- newArray (1,10) 0 
    bools <- newArray (1,20) False 
    char <- newSTRef 'X' 
    return $ WS ints bools char 

bar :: Char 
bar = runST $ do 
    WS ints bools char <- newWS 
    writeArray ints 3 36 
    writeArray bools 5 True 
    writeSTRef char 'Z' 
    -- ... 
    readSTRef char 

這種方法對於箱子評論(1)和(2)?那麼情況(3)呢?

baz :: (UArray Int Int, UArray Int Bool) 
baz = runST??? $ do 
    AP ints bools <- newAP 
    ... 
    return (ints,bools) -- ??? 

回答

3

你有2種選擇:

  1. 使用freeze。這需要複製陣列,但你並不需要使用任何不安全的功能:

    baz :: (UArray Int Int, UArray Int Bool) 
    baz = runST $ do 
        AP ints bools <- newAP 12 
        liftM2 (,) (freeze ints) (freeze bools) 
    
  2. 使用unsafeFreezeSTUArray兩個數組創建您的runSTUArray變種,知道實現是真正安全的(因爲不會有任何引用到原來的可變陣列左)。

    runSTUArray2 :: (Ix i1, Ix i2) 
          => (forall s . (ST s (STUArray s i1 e1, STUArray s i2 e2))) 
          -> (UArray i1 e1, UArray i2 e2) 
    runSTUArray2 st = runST $ do 
        (a1, a2) <- st 
        liftM2 (,) (unsafeFreezeSTUArray a1) (unsafeFreezeSTUArray a2) 
    
    baz' :: (UArray Int Int, UArray Int Bool) 
    baz' = runSTUArray2 $ do 
        AP ints bools <- newAP 12 
        return (ints, bools) 
    

    (也許這種做法可能會更莫名其妙使用泛型允許返回包含ST陣列的任何數據結構一概而論。)

+0

謝謝!我看到我現在迷失的地方。 – ErikR