IORef в Хаскеле - PullRequest
       29

IORef в Хаскеле

0 голосов
/ 23 сентября 2018

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

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

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

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

1 Ответ

0 голосов
/ 23 сентября 2018

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

(Если статья была о передовой практике для изменяемых ссылок или параллелизма, возможно, она была написана до того, как стали доступны лучшие альтернативы.)

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

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

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

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

По поводу ваших более конкретных вопросов:

  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 внутренние элементы дескриптора файла широко используют IORefs для прикрепления буферов к ручкам.Это хороший пример того, что «уже в монаде ввода-вывода с запутанными операциями ввода-вывода».
  • Многие векторные алгоритмы наиболее эффективно реализуются с использованием изменяемых векторов (например, даже таких простых, как подсчет байтовых частот в блокеданные).Если вы используете изменяемые векторы из пакета vector, то технически вы используете изменяемые байтовые массивы, а не STRef или IORef, но это все еще морально эквивалентно.
  • Пакет equivalence использует STRef s для эффективной реализации алгоритма union-join.
  • В качестве примера, если вы используете интерпретатор для императивного языка, тогда используйте IORef или * 1104.* значения для изменяемых переменных, как правило, будут наиболее эффективными.
...