Хорошо, начну с IORef
. IORef
предоставляет значение, которое может изменяться в монаде ввода-вывода. Это просто ссылка на некоторые данные, и, как и в любой другой ссылке, есть функции, позволяющие изменять данные, на которые она ссылается. В Haskell все эти функции работают в IO
. Вы можете думать об этом как о базе данных, файле или другом внешнем хранилище данных - вы можете получать и устанавливать данные в нем, но для этого требуется выполнение ввода-вывода. Причина, по которой ввод-вывод вообще необходим, состоит в том, что Haskell чист ; компилятору нужен способ узнать, на какие данные указывает ссылка в любой момент времени (прочтите сообщение в блоге sigfpe «Вы могли изобрести монады» ).
MVar
s - это в основном то же самое, что и IORef, за исключением двух очень важных отличий. MVar
является примитивом параллелизма, поэтому он предназначен для доступа из нескольких потоков. Второе отличие заключается в том, что это MVar
поле, которое может быть полным или пустым. Итак, если у IORef Int
всегда есть Int
(или внизу), у А MVar Int
может быть Int
или он может быть пустым. Если поток пытается прочитать значение из пустого MVar
, он будет блокироваться до тех пор, пока не MVar
будет заполнено (другим потоком). По сути, это MVar a
эквивалентно IORef (Maybe a)
с дополнительной семантикой, которая полезна для параллелизма.
State
- это монада, которая обеспечивает изменяемое состояние, не обязательно с вводом-выводом. Фактически, это особенно полезно для чистых вычислений. Если у вас есть алгоритм, который использует состояние, но не IO
используетState
монада часто оказывается элегантным решением.
Существует также версия монады трансформатора государства StateT
. Это часто используется для хранения данных конфигурации программы или типов состояний «игрового мира» в приложениях.
ST
что-то немного другое. Основная структура данных ST
- STRef
это объект, который похож на объект, IORef
но с другой монадой. ST
Система типа монады использует обман (в «государственных нитях» Документы упоминают) , чтобы гарантировать , что изменяемые данные не могут избежать монад; то есть, когда вы запускаете вычисление ST, вы получаете чистый результат. Причина, по которой ST интересен, заключается в том, что это примитивная монада, подобная IO, позволяющая вычислениям выполнять низкоуровневые манипуляции с байтовыми массивами и указателями. Это означает, что ST
можно обеспечить чистый интерфейс при использовании низкоуровневых операций с изменяемыми данными, то есть очень быстро. С точки зрения программы, это как если бы ST
вычисления выполнялись в отдельном потоке с локальным хранилищем потока.