IORef в Хаскеле

Мне было интересно, было ли законное использование IORef в Haskell? В частности, я был бы благодарен, если бы кто-то мог обратиться к следующему или указать подходящее место, чтобы узнать больше об этом:

  1. Считается ли использование IORef плохой практикой на Хаскеле? Если да, то почему? Точнее, чем она лучше или хуже монады ввода-вывода?
  2. Если кто-то хотел добавить состояние в программу, разве монада состояний не является лучшим (более чистым) способом сделать это. Если кто-то чувствует себя более настоятельным, не может ли он по-прежнему использовать STM и MVar, и все равно будет лучше?

  3. Существуют ли сценарии программирования, которые легко обрабатываются с использованием IORef, а не STM, MVar или чистого IO?

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

1 ответ

Решение

Во-первых, я думаю, что для фрагментов кода в документе, используя IORef вполне разумно, особенно если в статье не говорится о передовых методах изменчивых ссылок или параллелизма. IORef прост для понимания, имеет простой синтаксис и семантику (особенно в непараллельных настройках) и является естественным выбором, если вы хотите, чтобы читатель сосредоточился на аспектах ваших примеров, отличных от IORef s. Очень жаль, что авторский подход обернулся для вас неудачей - просто игнорируйте IORef s и обратите внимание на то, что остальное из того, что говорит газета.

.

В любом случае, к вашему большому вопросу, основные возражения против использования IORef было бы:

  • Как и любой другой механизм введения изменяемого состояния в вашу программу, он делает ваш код более трудным для рассуждения, сопровождения, тестирования и т. Д. - все обычные вещи, которые, как сказали бы сторонники функционального программирования, дают FP преимущество над интенсивным мутациями. императивные алгоритмы.
  • Это просто оболочка нового типа вокруг специализированной STRef RealWorld и единственное, что добавляет STRef некоторые атомные операции. В несовпадающем коде нет веских причин не использовать STRef s значения в ST s монада, так как они более гибкие - вы можете запустить их в чистом коде с runST или, при необходимости, в монаде IO с stToIO,
  • В параллельном коде есть более мощные абстракции, такие как MVar а также STM с которыми гораздо проще работать IORef s.

Таким образом, в той степени, в которой изменяемое состояние является "плохим" и - если вам это действительно нужно - доступны лучшие альтернативы в зависимости от того, нужен ли вам параллелизм или нет, рекомендовать особо нечего IORef,

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

Что касается ваших более конкретных вопросов:

  1. Я думаю, было бы с уверенностью сказать, что с помощью IORef считается "плохой практикой", когда более слабый инструмент сделает эту работу. Этот более слабый инструмент может быть STRef s или, еще лучше, State монада или, что еще лучше, переписанный алгоритм высшего порядка, который вообще не нуждается ни в каком состоянии. Так как IORef объединяет ввод-вывод с изменяемыми ссылками, это своего рода императивный кувалдой, который, вероятно, приведет к самому недиоматичному коду на Haskell, поэтому его лучше избегать, если только это "явно" не является правильным решением для конкретной проблемы.

  2. State Монада обычно является предпочтительным идиоматическим способом добавления состояния в программу, но она обеспечивает "иллюзию" изменчивого состояния, пропуская последовательность значений неизменяемого состояния посредством вычислений, и не все алгоритмы могут быть эффективно реализованы таким образом. Там, где требуется истинное изменяемое состояние, STRef Обычно это естественный выбор в условиях одновременности. Обратите внимание, что вы, вероятно, не будете использовать MVar или же STM в непараллельном режиме - в этом случае нет причин использовать их, и они заставят вас IO Монада, даже если она тебе не нужна.

  3. Да, есть сценарии программирования, где либо IORef или же STRef предпочтительнее State, STM, MVar или чистый IO (увидеть ниже). Есть несколько сценариев, где IORef очевидно предпочтительнее STRef, но - как уже упоминалось выше - если вы уже в IO монада и нуждаются в истинном изменяемом состоянии, которое запутано с операциями ввода-вывода, затем IORef вероятно, имеет преимущество над STRef с точки зрения немного более чистого синтаксиса.

Некоторые примеры случаев, когда либо IORef или же STRef хороший подход

  • Data.Unique в base пакет использует IORef в качестве глобального счетчика для генерации уникальных объектов.
  • в base библиотека, внутренние дескрипторы файлов широко используют IORef s для прикрепления буферов к ручкам. Это хороший пример "уже в монаде ввода-вывода с запутанными операциями ввода-вывода".
  • Многие векторные алгоритмы наиболее эффективно реализуются с использованием изменяемых векторов (например, даже таких простых вещей, как подсчет байтовых частот в блоке данных). Если вы используете изменяемые векторы из vector пакет, то технически вы используете изменяемые байтовые массивы, а не STRef или же IORef, но это все еще морально эквивалентно.
  • equivalence пакет использует STRef s для эффективной реализации алгоритма объединения-объединения.
  • Например, если вы используете переводчик для императивного языка, используйте IORef или же STRef Значения для изменяемых переменных, как правило, будут наиболее эффективными.
Другие вопросы по тегам