Как работает святая монада?
Я понимаю, что святая монада-это что-то вроде младшего брата Ио, который в свою очередь является государственной монадой с добавлением 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 отклонять программы, которые делают сомнительные вещи. (Это так называемый Фантом типа, вещь с только существует в голове проверки типа, и не влияет ни на что во время выполнения.)