新手和州/ ST相关问题的STArray文档

时间:2011-11-19 20:26:32

标签: arrays haskell state higher-rank-types

我很难从文档和我通过Google找到的其他howtos /讨论中了解STArray。我在下面有一些更相关的问题。

根据文档,STArray

  

ST monad中的可变盒装和未装箱阵列。

这给我的印象是,STArray意味着用作在函数之间传递的状态(想象你有一个必须经常更新的向量)。 / p>

显然,它的使用方式不同:

ST s (STArray s a e)

这里的州s是什么?如果它是在内部使用的,那么为什么这不会对用户隐藏呢?

这也意味着,如果我们想使用STArray s Int Int作为状态传递,则可以定义

type StateArray a = Control.Monad.State (ST s (STArray s Int Int)) a

这看起来相当麻烦。

最后,

  • STState之间的区别是什么?
  • 如果STArrayIOArray用于“内部”使用,STIO之间有什么区别?

谢谢!

1 个答案:

答案 0 :(得分:70)

ST是一个monad,其中允许有限类型的副作用,即可变引用和可变数组。因此,它允许您实现从外部世界看到的纯函数,但在内部使用变异。

这与State不同,State仅通过将计算状态作为额外输入和输出线程化来伪造突变。在实现一些命令性算法时,差异很重要,因为它们有时需要突变才能有效实施。例如,在ST monad中使用常规数组,您只能通过复制来修改它,而使用ST,您可以在原地进行真正的突变。

我们同时拥有IOST的原因是IO提供了比ST更强的保证,即:

  1. ST不允许任意副作用,例如访问文件系统。
  2. 我们可以保证runST 允许的副作用允许无法逃避s的范围,因此它可以被视为来自外部世界的纯粹。
  3. 我们可以保证副作用无法逃脱的原因与类型变量s有关。由于任何ST动作在runST中都必须是多态的,所以你不能编写允许任何可变引用进入或离开s范围的代码,因为类型检查器会抱怨它不能保证{您的操作的{1}}以及引用或数组的操作与相同,除非它们来自同一runST范围。

    作为将ST monad与可变数组一起使用的示例,以下是Erathostenes筛选的实现:

    import Control.Monad
    import Control.Monad.ST
    import Data.Array.ST
    import Data.Array.Unboxed
    
    primesUpto :: Int -> [Int]
    primesUpto n = [p | (p, True) <- assocs $ sieve n]
    
    sieve :: Int -> UArray Int Bool
    sieve n = runSTUArray $ do
        sieve <- newArray (2, n) True
        forM_ [2..n] $ \p -> do
            isPrime <- readArray sieve p
            when isPrime $ do
                forM_ [p*2, p*3 .. n] $ \k -> do
                    writeArray sieve k False
        return sieve
    

    runSTUArrayrunST的一种特殊形式,它允许您在冻结它并将其作为不可变数组返回之前使用内部变异构建数组。 newArrayreadArraywriteArray按您的意愿行事。

    正如您所看到的,sieve的类型签名表明它是一个纯函数,它是。但是,它在内部使用突变来有效地实现它。