Монады против стрел

Я широко знаком с понятиями monads и arrows, как используется в функциональном программировании. Я также понимаю, что они могут быть использованы для решения подобных проблем.

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

Когда я должен использовать монады и когда я должен использовать стрелки?

Ответ 1

Есть две отличные статьи Линдли, Вадлера и Яллопа (обсуждаются в LTU здесь).

Самое главное понять, что есть больше вещей, которые являются стрелками, чем есть вещи, которые являются монадами. И наоборот, монады строго сильнее, чем стрелки (вторая статья arr и pure соответственно.)

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


Вышеизложенная попытка была общей и описательной. Ниже приведены некоторые из моих упрямых эмпирических правил.

Если вам нужно смоделировать что-то похожее на состояние, начните с монады. Если вам нужно смоделировать что-то, что выглядит как глобальный поток управления (т.е. Исключения, продолжения), начните с монады. Если возникает требование, что конфликты с властью и общими модами (т.е. Для которых объединение (join :: m (m a) -> m a) слишком мощное), тогда подумайте о том, чтобы отрубить во власти вещи, которую вы используете.

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

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

Там, конечно, многое другое. Для аппликаций см. в частности, в Conal Elliott для работы с FRP. Для стрелок см. Библиотека XML-анализатора HXT, Проект YAPA FRP, Haskell на веб-основе для лошадей, Hudak и Liu classic "Например, с помощью прокладки" Космический утечек со стрелкой". Для монадов, см. Везде. И, конечно, обратите внимание, что только потому, что что-то является монадой, это не означает, что аппликативная нотация может быть не более ясной и выразительной.

Ответ 2

Короткий ответ заключается в том, что стрелки более общие, чем Monads, а также более громоздки в использовании. Таким образом, вы должны использовать Monads, когда можете, оставляя использование стрелок для случаев, когда Monads не применимы.

Далее следует ответ на "живописный маршрут".

Джон Хьюз, человек, который представил Arrows, опубликовал две замечательные статьи, которые я рекомендую: "Обобщающие монады стрелками" и "Программирование со стрелками" . Эти две статьи легко читаются и дают ответ на ваш вопрос. Даже если некоторые люди не понимают всех деталей или кода в этих двух статьях, они наверняка найдут много информации и очень полезные объяснения о Монадах и стрелках.

Теперь я выделим основные моменты из этих статей, которые относятся к вашему вопросу

Когда монады были представлены, люди думали, что они всемогущи. В самом деле, Монады собирают много энергии. Но в какой-то момент было обнаружено, что есть случаи, когда Монад нельзя применять. Эти случаи связаны с несколькими входами, особенно когда некоторые из входов являются статическими, а некоторые из входов являются динамическими. Итак, Джон Хьюз подошел и представил стрелки.

Стрелки более общие, чем Monads. Стрелки - это надмножество Монад. Они могут делать все, что делают Монады, и многое другое. Но они также сложнее в использовании. Джон Хьюз рекомендует использовать Monads каждый раз, когда можете, и что вы должны использовать стрелки, когда вы не можете использовать Monads.

Я согласен с Джоном Хьюзом. Мне также напоминает о цитате Эйнштейна "Все должно быть сделано максимально простым, но не простым".

Конечно, все зависит от конкретной ситуации. Позволь мне объяснить. Предположим, вы изучаете Haskell. Тогда было бы большой задачей делать каждую программу с использованием монадического подхода и повторять ее с использованием подхода на основе стрелок. Когда вы учитесь, вы должны стремиться исследовать все возможности и применять всевозможные подходы. Таким образом, вы получите отличное представление, и вы можете сравнить различные решения из первых рук.

Предположим теперь, что вы хотите предоставить библиотеку для сообщества. Ну, вы обязаны этим людям, которые прочтут ваш код, чтобы вы использовали подход, который легче всего понять и все еще выполняет свою работу. Вы также обязаны тем людям, которые будут использовать ваш код, чтобы ваше решение не нуждалось в излишней сложности. Таким образом, ваше решение более легко поддерживается и менее подвержено ошибкам и ошибкам.

Но что, если вы находитесь в пограничном случае? Предположим, вы не уверены, нужна ли вам дополнительная сила стрел. Тогда что вы должны делать? Если вы начнете с монадического подхода, а затем переключитесь на стрелочный, если возникнет такая необходимость? Или вы должны начать с стрелок с начала, избегая дорогостоящего переключения на полпути через проект?

Опять же, мой ответ - попробовать первый подход: попробуйте использовать Monads, если сможете. Если позже вы узнаете, что вы не можете использовать Monads, вам придется переносить дорогостоящий переключатель, где вам придется перезапустить и повторить проект, чтобы использовать стрелки. Этот подход, безусловно, потребует больше времени и других ресурсов с вашей стороны. Но вы будете знать, что вы сделали правильную вещь, которая должна была обеспечить самое простое, ясное и менее сложное решение.

Избежать ненужной сложности - самое главное. Верьте или нет, поэтому в "Информатике" были введены концепции (такие как композиция функций, моноды и стрелки) из теории категорий. Иронический?