Когда можно использовать IORef?
Одна вещь, которая всегда смущала меня, это то, что сейчас самое время использовать IORef. Существуют ли какие-либо рекомендации, которые следует соблюдать при принятии решения, использовать ли IORef для выполнения задачи? Когда подходящее время использовать государственную монаду над IORef?
4 ответа
State и его относительный ST производят "монолитные" вычисления с состоянием, которые могут выполняться как единицы. Они в основном рассматривают изменчивое состояние как промежуточные данные, которые необходимы для получения результата, но сами по себе не должны представлять интерес для остальной части программы.
С другой стороны, то, что вы помещаете в IORef, - это не "вычисление", которое нужно запустить - это просто блок, содержащий простое значение, которое может быть использовано в IO довольно произвольным образом. Это поле может быть помещено в структуры данных, передано (часть ввода-вывода) программы, заменено ее содержимое, когда это удобно, закрыто функцией и т. Д. На самом деле, довольно много беспорядочной природы переменных и указатели таких языков, как C, могут быть смоделированы с помощью IORefs, предоставляя большую помощь любому опытному программисту C, желающему сохранить свою репутацию способности писать код C на любом языке... Это то, что определенно следует использовать с осторожностью.
Тем не менее, порой крайне громоздко, если не совершенно невозможно, изолировать все взаимодействия с фрагментом изменяемого состояния в одном блоке кода - некоторые фрагменты состояния просто необходимо передать, поместить в структуры данных и т. Д. В таких случаях единственным подходом может быть коробочный подход. В главе, представляющей изменяемое состояние учебника "Напиши себе схему за 48 часов" (кстати, очень рекомендуется), приводится пример. (См. Ссылку для хорошего обсуждения того, почему на самом деле наиболее целесообразно использовать IORef, а не State или ST, для моделирования сред Scheme в определенной конструкции интерпретатора Scheme.)
Короче говоря, эти среды должны быть вложены произвольным образом, поддерживаться между случаями взаимодействия с пользователем ((define x 1)
набранный на схеме REPL, по-видимому, приведет к тому, что пользователь сможет впоследствии ввести x
и возвращаем 1 в качестве значения), помещаем внутрь объектов, моделирующих функции Scheme (поскольку функции Scheme близки по окружениям, в которых они созданы) и т. д.
Подводя итог, скажу, что если задача кажется вполне подходящей для нее, государство будет стремиться предоставить самое чистое решение. Если требуется несколько отдельных частей состояния, возможно, ST может помочь. Однако, если вычисление с состоянием является громоздким или невозможно заблокировать в своем собственном фрагменте кода, состояние должно сохраняться в изменяемой форме в течение большей части жизни сложной программы и т. Д., Тогда IORefs могут быть просто подходящая вещь.
Опять же, если вам нужен вид изменяемого состояния, которое может передаваться и взаимодействовать контролируемым образом с помощью кода ввода-вывода, почему бы не проверить STM и его TVars! Они гораздо приятнее при наличии параллелизма, настолько, что фактически делают решение некоторых задач, связанных с параллелизмом, действительно простым. Это, правда, не имеет отношения к вопросу, поэтому я не буду настаивать на уточнении.:-)
Хм. Вы будете использовать IORef, когда вам нужно какое-то изменяемое состояние, но вы находитесь в однопоточном окружении. Или когда вы хотите, чтобы изменяемое поле находилось внутри большей структуры, которая, в свою очередь, удерживается переменной синхронизации.
В общем, используйте MVars. У них более надежная семантика.
Лично я бы сказал, что это нормально IORef
когда и только когда вы уже используете IO
, В противном случае всегда State
, если вам не нужна превосходная производительность ST
, Можно использовать несколько потоков состояния с State
Монада, с несколькими вспомогательными функциями - вы просто делаете состояние кортежем или записью и определяете функции для установки, получения или обновления каждого поля отдельно.
В частности, нет особого смысла в использовании StateT s IO
, Если вы уже в IO
, у вас уже есть изменяемое состояние, так что вы можете использовать его - ReaderT (IORef s) IO
например.
Я использую STRef
когда состояние локализовано и не требует взаимодействия с окружающей средой.