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