Разница между State, ST, IORef и MVar



Я работаю через напишите себе схему за 48 часов (Я до 85 часов), и я добрался до части о добавление переменных и задания. В этой главе есть большой концептуальный скачок, и я хотел бы, чтобы это было сделано в два этапа с хорошим рефакторингом между ними, а не прыгать прямо к окончательному решению. В любом случае...



Я заблудился с несколькими различными классами, которые, кажется, служат одной и той же цели: State, ST,IORef и MVar. Первые три упоминаются в тексте, в то время как последний, по-видимому, является предпочтительным ответом на многие вопросы StackOverflow о первых трех. Все они, кажется, несут состояние между последовательными вызовами.



что каждый из них и чем они отличаются друг от друга?





в частности, эти предложения не имеют смысла:




вместо этого мы используем функцию под названием государство threads, позволяя Haskell управлять агрегатным состоянием для нас. Это позволяет нам обрабатывать изменяемые переменные, как и в любом другом языке программирования, используя функции для получения или установки переменных.




и




модуль IORef позволяет использовать переменные с отслеживанием состояния в монаду IO.




все это делает строку type ENV = IORef [(String, IORef LispVal)] непонятно, почему второй IORef? Что сломается, если я напишу type ENV = State [(String, LispVal)] вместо этого?

677   3  

3 ответов:

Монада состояния: модель изменчивого состояния

монада состояния-это чисто функциональная среда для программ с состоянием, с простым API:

  • get
  • поставить

документация пакет mtl.

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

святая монада и Стрефы

ST монада является ограниченным двоюродным братом монады IO.

это позволяет произвольно государство-изменчивый, реализовано как фактическая изменяемая память на машине. API-интерфейс выполнен в безопасный побочный эффект-бесплатных программ, поскольку параметр типа rank-2 предотвращает выход значений, зависящих от изменяемого состояния, из локальной области.

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

обычно используется для изменяемых массивов и других структур данных, которые мутируют, а затем замораживаются. Это также очень эффективно, так как изменчивое состояние является "аппаратным ускорением".

основной API:

  • Control.Monad.ST
  • runST -- start a новое вычисление эффекта памяти.
  • и STRefs: указатели на (локальные) изменяемые ячейки.
  • St-основанные массивы (такие как вектор) также распространены.

думайте об этом как о менее опасном брате монады ИО. Или IO, где вы можете только читать и записывать в память.

IORef: STRefs in IO

Это STRefs (см. выше) в монаде IO. Они не имеют такие же гарантии безопасности как STRefs около местность.

MVars : IORefs с замками

Как STRefs или IORefs, но с замком прилагается, для безопасного одновременно доступ из нескольких потоков. IORefs и STRefs используются только безопасные в многопоточной установки при использовании atomicModifyIORef (атомарная операция сравнения и замены). MVars-это более общий механизм безопасного совместного использования изменяемого состояния.

вообще, в Haskell, используйте MVars или TVars (STM-based mutable cells), над STRef или Выводе ioref.

хорошо, я начну с IORef. IORef предоставляет значение, которое является изменяемым в монаде ввода-вывода. Это просто ссылка на некоторые данные, и, как и любая ссылка, есть функции, которые позволяют изменять данные, на которые она ссылается. В Haskell, все эти функции работают в IO. Вы можете думать об этом как о базе данных, файле или другом внешнем хранилище данных - вы можете получить и установить данные в нем, но для этого требуется пройти через IO. Причина ИО необходимо на все это, потому что Хаскелл чисто; компилятор должен знать, на какие данные указывает ссылка в любой момент времени (read сигнала sigfpe "ты мог бы придумать монады" blogpost).

MVars в основном то же самое, что и IORef, за исключением двух очень важных различий. MVar - это параллелизм примитивно, поэтому он предназначен для доступа из нескольких потоков. Второе отличие заключается в том, что MVar это коробка, которая может быть полной или пустой. Так где же IORef Int всегда имеет Int (или внизу), an MVar Int может быть Int или он может быть пустым. Если поток пытается прочитать значение из пустого MVar, он будет блокировать до тех пор, пока MVar заполняется (другим потоком). В основном это MVar a эквивалентно IORef (Maybe a) С дополнительной семантикой, которая полезна для параллелизма.

State это монада, которая обеспечивает изменчивое состояние, не обязательно с IO. На самом деле, это особенно полезно для чистых вычислений. Если у вас есть алгоритм это использует состояние, но не IO, a State монада часто является элегантным решением.

существует также версия трансформатора монады состояния,StateT. Это часто используется для хранения данных конфигурации программы или типов состояния" игровой мир " в приложениях.

ST немного другое. Основная структура данных в ST - это STRef, что похоже на IORef но с другой монады. Элемент ST монада использует тип системы обман ("потоки состояний", упомянутые в документах), чтобы гарантировать, что изменяемые данные не могут избежать монады; то есть, когда вы запускаете вычисление ST, вы получаете чистый результат. Причина St интересна тем, что это примитивная монада, подобная IO, позволяющая вычислениям выполнять низкоуровневые манипуляции на bytearrays и указателях. Это значит, что ST может обеспечить чистый интерфейс при использовании низкоуровневых операций с изменяемыми данными, что означает, что это очень быстро. С точки зрения программы, это как если бы элемент ST расчет выполняется в отдельном потоке с локальной памятью потока.

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

все это делает тип строка ENV = IORef [(String, IORef LispVal)] запутанным. Почему второй выводе ioref? Что? сломается, если я сделаю type ENV = State [(String, LispVal)] вместо?

Lisp-это функциональный язык с изменяемым состоянием и лексической областью. Представьте, что вы закрыли над изменяемой переменной. Теперь у вас есть ссылка на эту переменную, висящую внутри какой-то другой функции-скажем (в псевдокоде в стиле Хаскелла) (printIt, setIt) = let x = 5 in (\ () -> print x, \y -> set x y). Теперь у вас есть две функции-одна печатает x, а другая устанавливает его значение. Когда вы оцениваете printIt, вы хотите найти имя x в начальной среде, в которой printIt был определен, но вы хотите, чтобы поиск стоимостью это имя привязано к среде, в которой printIt - это под названием (после setIt может быть вызвано любое количество раз).

есть способы, кроме двух IORefs, чтобы сделать это, но вам, конечно, нужно больше чем последний тип, который вы предложили, который не позволяет вам изменять значения, к которым привязаны имена в лексически ограниченном виде. Google "проблема funargs" для целого ряда интересных предысторий.

Comments

    Ничего не найдено.