我很难从文档和我通过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
这看起来相当麻烦。
最后,
ST
和State
之间的区别是什么?STArray
和IOArray
用于“内部”使用,ST
和IO
之间有什么区别?谢谢!
答案 0 :(得分:70)
ST
是一个monad,其中允许有限类型的副作用,即可变引用和可变数组。因此,它允许您实现从外部世界看到的纯函数,但在内部使用变异。
这与State
不同,State
仅通过将计算状态作为额外输入和输出线程化来伪造突变。在实现一些命令性算法时,差异很重要,因为它们有时需要突变才能有效实施。例如,在ST
monad中使用常规数组,您只能通过复制来修改它,而使用ST
,您可以在原地进行真正的突变。
我们同时拥有IO
和ST
的原因是IO
提供了比ST
更强的保证,即:
ST
不允许任意副作用,例如访问文件系统。runST
允许的副作用允许无法逃避s
的范围,因此它可以被视为来自外部世界的纯粹。我们可以保证副作用无法逃脱的原因与类型变量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
runSTUArray
是runST
的一种特殊形式,它允许您在冻结它并将其作为不可变数组返回之前使用内部变异构建数组。 newArray
,readArray
和writeArray
按您的意愿行事。
正如您所看到的,sieve
的类型签名表明它是一个纯函数,它是。但是,它在内部使用突变来有效地实现它。