Как работает святая монада?
Я понимаю, что святая монада-это что-то вроде младшего брата Ио, который в свою очередь является государственной монадой с добавлением RealWorld
магия. Я могу представить себе состояния, и я могу представить, что реальный мир каким-то образом помещается в IO, но каждый раз, когда я пишу подпись типа ST
the s
из Святой монады смущает меня.
Возьмем, например, ST s (STArray s a b)
. Как это s
там работать? Он просто используется для создания некоторой искусственной зависимости данных между вычислениями, не имея возможности чтобы ссылаться как состояния в монаде состояния (из-за forall
)?
Я просто выбрасываю идеи и был бы очень признателен кому-то более знающему, чем я, чтобы объяснить мне это.
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
или эквивалент, за кулисами. Причина, по которой вы можете сделать это безопасно, заключается в сигнатуре типа allST
- связанные функции, особенно часть сforall
.
на
s
Это просто хак, который делает тип системы остановить вас делать то, что было бы небезопасно. Он ничего не "делает" во время выполнения; он просто заставляет type checker отклонять программы, которые делают сомнительные вещи. (Это так называемый Фантом типа, вещь с только существует в голове проверки типа, и не влияет ни на что во время выполнения.)