Подтвердить что ты не робот

Документация STArray для новичков и вопросов, связанных с государством/ST

Мне трудно понять STArray из документации и других действий/обсуждений, которые я нашел через Google. У меня есть еще несколько связанных вопросов.

Согласно документации, STArray

Mutable boxed и unboxed массивы в монаде ST.

Мне показалось, что STArray предполагается использовать как состояние, передаваемое между функциями (представьте, что у вас есть вектор, который нужно часто обновлять).

По-видимому, это используется по-разному:

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 предназначены для использования "внутри"?

Спасибо!

4b9b3361

Ответ 1

ST - монада, в которой допускаются ограниченный тип побочных эффектов, а именно изменяемые ссылки и изменяемые массивы. Таким образом, он позволяет реализовать функции, которые являются чистыми, как видно из внешнего мира, но которые используют мутацию внутри.

Это отличается от State, что только подделывает мутацию путем потоковой передачи состояния через ваши вычисления в качестве дополнительных входов и выходов. Разница важна при реализации некоторых императивных алгоритмов, потому что иногда требуется, чтобы мутация была эффективно реализована. Например, используя обычный массив в монаде State, вы можете изменить его только путем создания копии, тогда как с ST вы можете иметь истинную мутацию на месте.

Причина, по которой мы имеем ST и IO, состоит в том, что ST обеспечивает более высокие гарантии, чем IO, а именно:

  • ST не разрешает произвольные побочные эффекты, например, например, доступ к файловой системе.
  • Мы можем гарантировать, что побочные эффекты ST действительно не позволяют избежать объема runST, и поэтому его можно рассматривать как чистое из внешнего мира.

Причина, по которой мы можем гарантировать, что побочные эффекты не могут выйти, связана с переменной типа s. Поскольку любое действие ST должно быть полиморфным в s, вы не можете писать код, который позволяет любым изменяемым ссылкам вводить или покидать область runST, так как средство проверки типов будет жаловаться на то, что оно не может гарантировать, что s вашего действие и значение ссылки или массива одинаковы, если они не относятся к той же области runST.

В качестве примера использования монады ST с изменяемыми массивами приведена реализация сита эратостен:

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 указывает, что это чистая функция, и она есть. Однако он активно использует мутацию внутри, чтобы эффективно реализовать ее.