arrays - 使用并返回多个 STUArray

标签 arrays haskell st-monad

我一直在研究如何在 ST 计算中创建和使用多个 STUArray。具体场景为:

  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)  -- ???

最佳答案

您有 2 个选择:

  1. 使用卡住。这需要复制数组,但不需要使用任何不安全的函数:

    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 数组的任何数据结构。)

关于arrays - 使用并返回多个 STUArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21915204/

相关文章:

haskell - 为什么我的程序在播放光泽动画后立即退出?

haskell - `State#` 的规范

dictionary - 用于在 map 上插入和总查找的 Monad 转换器?

javascript - 使用 Javascript reduce 根据主题将文章数组拆分为子数组

c - 如何管理 C 函数中的任意参数

Haskell 安全资金示例

haskell - Haskell 中并行计算的性能问题

haskell - 需要 MonadPlus (ST a) 实例

python - 对数组中所有元素的范围内的元素求和

java - 通过java邮件发送带有包含byte[]附件的电子邮件