我一直在研究如何在 ST 计算中创建和使用多个 STUArray。具体场景为:
- 创建多个数组但仅返回其中一个
- 创建多个数组但不返回任何数组
- 创建多个数组并返回多个数组
我有 (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) -- ???
最佳答案
您有 2 个选择:
使用
卡住
。这需要复制数组,但不需要使用任何不安全的函数:baz :: (UArray Int Int, UArray Int Bool) baz = runST $ do AP ints bools <- newAP 12 liftM2 (,) (freeze ints) (freeze bools)
使用
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
数组的任何数据结构。)
关于arrays - 使用并返回多个 STUArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21915204/