it-roy-ru.com

Когда можно использовать IORef?

Одна вещь, которая всегда смущала меня, это то, что сейчас самое время использовать IORef. Существуют ли какие-либо рекомендации, которые следует соблюдать при принятии решения, использовать ли IORef для задачи? Когда подходящее время использовать государственную монаду над IORef?

59
Rayne

State и его относительный ST производят "монолитные" вычисления с состоянием, которые могут выполняться как единицы. Они в основном рассматривают изменчивое состояние как промежуточные данные, которые необходимы для получения результата, но сами по себе не должны представлять интерес для остальной части программы.

С другой стороны, то, что помещается внутрь IORef, - это не "вычисление", которое нужно запустить, - это просто блок, содержащий простое значение, которое может быть использовано внутри IO довольно произвольным образом. Это поле может быть помещено в структуры данных, обведено (часть ввода-вывода) программы, заменено ее содержимое, когда это удобно, закрыто функцией и т.д. На самом деле, довольно много беспорядочной природы переменных и указатели таких языков, как C, могут быть смоделированы с помощью IORefs, предоставляя большую помощь любому опытному программисту C, желающему поддержать свою репутацию способности писать код C на любом языке ... Это то, что определенно следует использовать с осторожностью.

Тем не менее, иногда чрезвычайно громоздко, если не совершенно невозможно, изолировать все взаимодействия с фрагментом изменяемого состояния в одном блоке кода - некоторые куски состояния просто необходимо обойти, поместить в структуры данных и т. д. В таких случаях единственно возможный вариант - блочный подход. Пример глава, посвященная изменчивому состоянию учебного пособия "Напиши себе схему за 48 часов" (кстати, очень рекомендуется). (См. Ссылку для хорошего обсуждения того, почему на самом деле наиболее целесообразно использовать IORefs, а не State или ST, для моделирования сред Scheme в определенной конструкции интерпретатора Scheme.)

Короче говоря, эти среды должны быть вложены произвольным образом и поддерживаться между экземплярами взаимодействия с пользователем ((define x 1), напечатанный на схеме REPL, должен, вероятно, привести к тому, что пользователь сможет позже ввести x и получить обратно 1) в качестве значения), поместите внутрь объектов моделирование функций Scheme (поскольку функции Scheme близки по окружениям, в которых они созданы) и т. д.

Подводя итог, скажу, что если задача кажется вполне подходящей для нее, государство будет стремиться предоставить самое чистое решение. Если требуется несколько отдельных частей состояния, возможно, ST может помочь. Однако, если вычисление с сохранением состояния громоздко или невозможно заблокировать в своем собственном фрагменте кода, состояние должно сохраняться в изменяемой форме в течение большей части жизни сложной программы и т.д., Тогда IORefs могут быть просто подходящая вещь.

Опять же, если вам нужно что-то вроде изменяемого состояния, которое может передаваться и взаимодействовать контролируемым образом с помощью кода IO, почему бы не проверить STM и его TVars! Они гораздо приятнее при наличии параллелизма, настолько, что фактически делают решение некоторых задач, связанных с параллелизмом, действительно простым. Это, правда, не имеет отношения к вопросу, поэтому я не буду настаивать на уточнении. :-)

73
Michał Marczyk

Хм. Вы бы использовали IORef, когда вам нужно какое-то изменяемое состояние, но в однопоточном окружении. Или когда вы хотите, чтобы изменяемое поле находилось внутри более крупной структуры, которая, в свою очередь, поддерживается переменной синхронизации.

В общем, используйте MVars. У них более надежная семантика.

14
Don Stewart

Лично я бы сказал, что можно использовать IORefs, когда и только когда вы уже используете IO. В противном случае всегда State, если вам не нужна превосходная производительность ST. Можно использовать несколько потоков состояний с монадой State с несколькими вспомогательными функциями - вы просто делаете состояние кортежем или записью и определяете функции для установки, получения или обновления каждого поля отдельно.

В частности, обычно нет особого смысла в использовании StateT s IO. Если вы уже находитесь в IO, у вас уже есть изменяемое состояние, так что вы также можете использовать его - например, ReaderT (IORef s) IO.

3
Ben Millwood

Я использую STRef, когда состояние локализовано и не требует взаимодействия со средой.

1
newacct