Как работает святая монада?


Я понимаю, что святая монада-это что-то вроде младшего брата Ио, который в свою очередь является государственной монадой с добавлением RealWorld магия. Я могу представить себе состояния, и я могу представить, что реальный мир каким-то образом помещается в IO, но каждый раз, когда я пишу подпись типа ST the s из Святой монады смущает меня.

Возьмем, например, ST s (STArray s a b). Как это s там работать? Он просто используется для создания некоторой искусственной зависимости данных между вычислениями, не имея возможности чтобы ссылаться как состояния в монаде состояния (из-за forall)?

Я просто выбрасываю идеи и был бы очень признателен кому-то более знающему, чем я, чтобы объяснить мне это.

2 64

2 ответа:

The s сохраняет объекты внутри ST монада от утечки наружу ST монады.

-- This is an error... but let's pretend for a moment...
let a = runST $ newSTRef (15 :: Int)
    b = runST $ writeSTRef a 20
    c = runST $ readSTRef a
in b `seq` c

хорошо, это ошибка типа (что хорошо! мы не хотим STRef утечка за пределы исходного вычисления!). Это ошибка типа из-за дополнительного s. Помните, что runST и подпись:

runST :: (forall s . ST s a) -> a

это означает, что s на вычислении, которое вы выполняете, не должно быть никаких ограничений на него. Так что когда вы попробуйте оценить a:

a = runST (newSTRef (15 :: Int) :: forall s. ST s (STRef s Int))

результат будет иметь тип STRef s Int, что неправильно, так как s "сбежал" за пределы forall на runST. Переменные типа всегда должны появляться внутри тега forall, и Haskell позволяет неявно forall кванторы везде. Там просто нет правила, которое позволяет вам осмысленно выяснить тип возврата a.

еще один пример с forall: чтобы ясно показать, почему вы не можете позволить вещам избежать forall, вот простой пример:

f :: (forall a. [a] -> b) -> Bool -> b
f g flag =
  if flag
  then g "abcd"
  else g [1,2]

> :t f length
f length :: Bool -> Int

> :t f id
-- error --

конечно f id это ошибка, так как он вернет либо список Char или список Int в зависимости от того, является ли логическое значение true или false. Это просто неправильно, как и в Примере с ST.

с другой стороны, если у вас не было s тип параметра, то все будет тип проверки просто отлично, хотя код, очевидно, довольно фальшиво.

как ST на самом деле работает: реализация-мудрый,ST монада на самом деле то же самое, что и IO монада, но с немного другим интерфейсом. Когда вы используете ST монада вы на самом деле получите unsafePerformIO или эквивалент, за кулисами. Причина, по которой вы можете сделать это безопасно, заключается в сигнатуре типа all ST - связанные функции, особенно часть с forall.

на s Это просто хак, который делает тип системы остановить вас делать то, что было бы небезопасно. Он ничего не "делает" во время выполнения; он просто заставляет type checker отклонять программы, которые делают сомнительные вещи. (Это так называемый Фантом типа, вещь с только существует в голове проверки типа, и не влияет ни на что во время выполнения.)