IORef в Хаскеле
Мне было интересно, было ли законное использование IORef в Haskell? В частности, я был бы благодарен, если бы кто-то мог обратиться к следующему или указать подходящее место, чтобы узнать больше об этом:
- Считается ли использование IORef плохой практикой на Хаскеле? Если да, то почему? Точнее, чем она лучше или хуже монады ввода-вывода?
Если кто-то хотел добавить состояние в программу, разве монада состояний не является лучшим (более чистым) способом сделать это. Если кто-то чувствует себя более настоятельным, не может ли он по-прежнему использовать STM и MVar, и все равно будет лучше?
Существуют ли сценарии программирования, которые легко обрабатываются с использованием 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
кажется законным.
Что касается ваших более конкретных вопросов:
Я думаю, было бы с уверенностью сказать, что с помощью
IORef
считается "плохой практикой", когда более слабый инструмент сделает эту работу. Этот более слабый инструмент может бытьSTRef s
или, еще лучше,State
монада или, что еще лучше, переписанный алгоритм высшего порядка, который вообще не нуждается ни в каком состоянии. Так какIORef
объединяет ввод-вывод с изменяемыми ссылками, это своего рода императивный кувалдой, который, вероятно, приведет к самому недиоматичному коду на Haskell, поэтому его лучше избегать, если только это "явно" не является правильным решением для конкретной проблемы.State
Монада обычно является предпочтительным идиоматическим способом добавления состояния в программу, но она обеспечивает "иллюзию" изменчивого состояния, пропуская последовательность значений неизменяемого состояния посредством вычислений, и не все алгоритмы могут быть эффективно реализованы таким образом. Там, где требуется истинное изменяемое состояние,STRef
Обычно это естественный выбор в условиях одновременности. Обратите внимание, что вы, вероятно, не будете использоватьMVar
или жеSTM
в непараллельном режиме - в этом случае нет причин использовать их, и они заставят васIO
Монада, даже если она тебе не нужна.Да, есть сценарии программирования, где либо
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
Значения для изменяемых переменных, как правило, будут наиболее эффективными.