Монады против Стрелок - PullRequest
       31

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

69 голосов
/ 06 сентября 2010

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

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

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

Ответы [ 2 ]

71 голосов
/ 08 сентября 2010

Есть две превосходные статьи Линдли, Уодлера и Яллопа (обсуждаемые здесь: LTU здесь ).

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

В частности, монады - это стрелки, снабженные функцией apply типа (a ~> b, a) ~> b, где (~>) - конструктор для данной стрелки. Линдли и соавт. отметьте, что это разрушает тщательное разграничение стрел между терминами и командами (или, если хотите, объектами и морфизмами).

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

По моему опыту, поскольку монады стирают различие между объектами и морфизмами (то есть, если я правильно использую слова, порождают закрытую декартову категорию), то термин в монаде обычно гораздо более непрозрачен, чем термин в стрелке или аппликативный функтор (хотя обратите внимание, что оба позволяют вводить произвольные функции методами arr и pure соответственно).

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


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

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

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

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

Там, конечно, гораздо больше истории. Относительно аппликативов см., В частности, работу Конала Эллиота по FRP Стрелки см. В библиотеке синтаксического анализатора HXT , проекте Yampa FRP , Haskell on a Horse: веб-фреймворк , классическое подключение Худака и Лю * Космическая утечка со стрелкой " бумага, между прочим. Для монад смотрите везде. И, конечно, обратите внимание, что если что-то является монадой, это не означает, что аппликативная запись не может быть более четкой и выразительной.

15 голосов
/ 09 августа 2014

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

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

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

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

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

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

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

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

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

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

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

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

...