STArray文件为新人和国家/ST相关问题

时间:2021-01-25 17:02:38

I have a hard time to understand STArray from the documentation and other howtos/discussion I've found through Google. I've got some more related questions below.

我很难从文档和通过谷歌找到的其他方法/讨论中理解STArray。下面我还有一些相关的问题。

According to the documentation, STArrays are

根据文献记载,星光是

Mutable boxed and unboxed arrays in the ST monad.

ST monad中的可变盒装和非盒装数组。

This gave me the impression, that STArray is meant to be used as a state being passed around between functions (imagine you have a vector that has to be updated often).

这给了我一个印象,STArray是用来作为一个在函数之间传递的状态(假设您有一个必须经常更新的向量)。

Apparently this is used differently though:

显然,这是不同的用法:

ST s (STArray s a e)

What is the state s here? If it is used internally, then why is this not hidden from the user?

这里的状态是什么?如果是内部使用,那么为什么不向用户隐藏呢?

This also means, if we want to use a STArray s Int Int being passed around as state, one would define

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

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

which seems rather cumbersome.

这似乎有点麻烦。

Finally,

最后,

  • what is the difference between ST and State?
  • ST和State的区别是什么?
  • what is the difference between STArray and IOArray, if the ST and IO are meant for "internal" use?
  • 如果ST和IO是用于“内部”使用,那么STArray和IOArray有什么区别呢?

Thank you!!

谢谢你! !

1 个解决方案

#1


68  

ST is a monad in which a limited type of side effects are allowed, namely mutable references and mutable arrays. Thus it allows you to implement functions which are pure as seen from the outside world, but which use mutation internally.

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

This is different from State, which only fakes mutation by threading the state through your computation as extra inputs and outputs. The difference is important when implementing some imperative algorithms, because they sometimes need mutation to be implemented efficiently. For example using a regular array in a State monad, you can only modify it by making a copy, whereas with ST you can have true mutation in-place.

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

The reason why we have both ST and IO is that ST provides stronger guarantees than IO, namely:

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

  1. ST does not allow arbitrary side effects like for example accessing the file system.
  2. ST不允许任意的副作用,例如访问文件系统。
  3. We can guarantee that the side effects ST does allow cannot escape the scope of runST, and so it can be seen as pure from the outside world.
  4. 我们可以保证ST所允许的副作用不能脱离runST的范围,因此可以从外部世界看它是纯粹的。

The reason why we can guarantee that the side effects cannot escape is related to the type variable s. Since any ST action must be polymorphic in s, you cannot write code which allows any mutable references to enter or leave the scope of a runST, because the type checker will complain that it cannot guarantee that the s of your action and that of the reference or array are the same unless they come from the same runST scope.

我们可以保证副作用的原因无法逃脱类型变量s。因为任何有关圣行动必须多态的年代,你不能写代码,允许任何可变引用进入或离开runST的范围,因为类型检查器会抱怨它不能保证你行动的年代和引用或数组都是相同的,除非他们来自同一个runST范围。

As an example of using the ST monad with mutable arrays, here is an implementation of the Sieve of Erathostenes:

作为使用可变数组的ST monad的一个例子,下面是伊拉斯托内斯筛子的实现:

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 is a specialized form of runST which allows you to build an array using mutation on the inside, before freezing it and returning it as an immutable array. newArray, readArray and writeArray do what you'd expect.

runSTUArray是runST的一种特殊形式,它允许您在内部使用突变构建一个数组,然后将其冻结,并将其作为不可变数的数组返回。newArray, readArray和writeArray做你想做的事情。

As you can see, the type signature of sieve indicates that it's a pure function, and it is. However, it uses mutation heavily on the inside to implement it efficiently.

正如您所看到的,筛选器的类型签名表示它是一个纯函数,它是。然而,它在内部大量使用突变来有效地实现它。

#1


68  

ST is a monad in which a limited type of side effects are allowed, namely mutable references and mutable arrays. Thus it allows you to implement functions which are pure as seen from the outside world, but which use mutation internally.

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

This is different from State, which only fakes mutation by threading the state through your computation as extra inputs and outputs. The difference is important when implementing some imperative algorithms, because they sometimes need mutation to be implemented efficiently. For example using a regular array in a State monad, you can only modify it by making a copy, whereas with ST you can have true mutation in-place.

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

The reason why we have both ST and IO is that ST provides stronger guarantees than IO, namely:

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

  1. ST does not allow arbitrary side effects like for example accessing the file system.
  2. ST不允许任意的副作用,例如访问文件系统。
  3. We can guarantee that the side effects ST does allow cannot escape the scope of runST, and so it can be seen as pure from the outside world.
  4. 我们可以保证ST所允许的副作用不能脱离runST的范围,因此可以从外部世界看它是纯粹的。

The reason why we can guarantee that the side effects cannot escape is related to the type variable s. Since any ST action must be polymorphic in s, you cannot write code which allows any mutable references to enter or leave the scope of a runST, because the type checker will complain that it cannot guarantee that the s of your action and that of the reference or array are the same unless they come from the same runST scope.

我们可以保证副作用的原因无法逃脱类型变量s。因为任何有关圣行动必须多态的年代,你不能写代码,允许任何可变引用进入或离开runST的范围,因为类型检查器会抱怨它不能保证你行动的年代和引用或数组都是相同的,除非他们来自同一个runST范围。

As an example of using the ST monad with mutable arrays, here is an implementation of the Sieve of Erathostenes:

作为使用可变数组的ST monad的一个例子,下面是伊拉斯托内斯筛子的实现:

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 is a specialized form of runST which allows you to build an array using mutation on the inside, before freezing it and returning it as an immutable array. newArray, readArray and writeArray do what you'd expect.

runSTUArray是runST的一种特殊形式,它允许您在内部使用突变构建一个数组,然后将其冻结,并将其作为不可变数的数组返回。newArray, readArray和writeArray做你想做的事情。

As you can see, the type signature of sieve indicates that it's a pure function, and it is. However, it uses mutation heavily on the inside to implement it efficiently.

正如您所看到的,筛选器的类型签名表示它是一个纯函数,它是。然而,它在内部大量使用突变来有效地实现它。