Хорошо, начну с IORef. IORefпредоставляет значение, которое может изменяться в монаде ввода-вывода. Это просто ссылка на некоторые данные, и, как и в любой другой ссылке, есть функции, позволяющие изменять данные, на которые она ссылается. В Haskell все эти функции работают в IO. Вы можете думать об этом как о базе данных, файле или другом внешнем хранилище данных - вы можете получать и устанавливать данные в нем, но для этого требуется выполнение ввода-вывода. Причина, по которой ввод-вывод вообще необходим, состоит в том, что Haskell чист ; компилятору нужен способ узнать, на какие данные указывает ссылка в любой момент времени (прочтите сообщение в блоге sigfpe «Вы могли изобрести монады» ).
MVars - это в основном то же самое, что и 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вычисления выполнялись в отдельном потоке с локальным хранилищем потока.