Объяснение комбинаторов для работающего человека - PullRequest
89 голосов
/ 23 сентября 2011

Что такое комбинатор ??

Является ли «функцией или определением без свободных переменных» (как определено в SO)?

Или как об этом: согласно Джону Хьюзу в его известной статье о стрелках, "комбинатор - это функция, которая строит фрагменты программы из фрагментов программы" , которая Это выгодно, потому что «... программист, использующий комбинаторы, создает большую часть желаемой программы автоматически, а не пишет каждую деталь вручную». Далее он говорит, что map и filter являются двумя распространенными примерами таких комбинаторов.

Некоторые комбинаторы, которые соответствуют первому определению:

Некоторые комбинаторы, которые соответствуют второму определению:

  • карта
  • фильтр
  • сложить / уменьшить (предположительно)
  • any of >> =, compose, fmap ?????

Меня не интересует первое определение - оно не помогло бы мне написать настоящую программу (+1, если вы убедите меня, что я неправ). Пожалуйста, помогите мне понять второе определение . Я думаю, что карты, фильтры и сокращения полезны: они позволяют мне программировать на более высоком уровне - меньше ошибок, более короткий и понятный код. Вот некоторые мои конкретные вопросы о комбинаторах:

  1. Какие еще примеры комбинаторов, таких как map, filter?
  2. Какие комбинаторы часто используют языки программирования?
  3. Как комбинаторы могут помочь мне разработать лучший API?
  4. Как создать эффективные комбинаторы?
  5. На что похожи комбинаторы в нефункциональном языке (скажем, Java) или что эти языки используют вместо комбинаторов?

Обновление

Благодаря @C. А. Макканн, теперь я немного лучше понимаю комбинаторы. Но один вопрос все еще остается камнем преткновения для меня:

В чем разница между функциональной программой, написанной с, и программой, написанной без интенсивного использования комбинаторов?

Я подозреваю, что ответ состоит в том, что версия для комбинатора более короткая, более четкая, более общая, но я был бы признателен за более углубленное обсуждение, если это возможно.

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

1 Ответ

91 голосов
/ 24 сентября 2011

Меня не интересует первое определение - оно не помогло бы мне написать настоящую программу (+1, если вы убедите меня, что я неправ). Пожалуйста, помогите мне понять второе определение. Я думаю, что карты, фильтры и сокращения полезны: они позволяют мне программировать на более высоком уровне - меньше ошибок, более короткий и ясный код.

Два определения в основном одно и то же. Первый основан на формальном определении, и вы приводите примеры примитивных комбинаторов - наименьших возможных строительных блоков. Они могут помочь вам написать настоящую программу, поскольку с их помощью вы можете создавать более сложные комбинаторы. Думайте о комбинаторах, таких как S и K, как о машинном языке гипотетического «комбинаторного компьютера». Конечно, настоящие компьютеры не работают таким образом, поэтому на практике вы обычно выполняете операции более высокого уровня за кулисами другими способами, но концептуальная основа все еще является полезным инструментом для понимания значения из этих операций более высокого уровня.

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

Какие еще примеры комбинаторов, таких как map, filter?

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

Какие комбинаторы часто используют языки программирования?

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

Как комбинаторы могут помочь мне разработать лучший API?

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

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

Как мне создать эффективные комбинаторы?

Сначала подумайте, какие операции имеют смысл для любых данных, которые использует ваша программа.Затем подумайте о том, как эти операции могут быть осмысленно объединены общими способами, а также о том, как операции можно разбить на более мелкие части, соединенные вместе.Главное - работать с преобразованиями и операциями , а не с прямыми действиями .Если у вас есть функция, которая просто выполняет некоторые сложные функции непрозрачным способом и выдает только какой-то предварительно обработанный результат, вы мало что можете сделать с этим.Оставьте окончательные результаты для кода, который использует комбинаторов - вы хотите, чтобы вещи переносили вас из точки А в точку Б, а не вещи, которые ожидают быть началом или концом процесса.

На что похожи комбинаторы в нефункциональном языке (скажем, Java) или что эти языки используют вместо комбинаторов?

Ахахахаха.Забавно, что вы должны спросить, потому что объекты - это действительно вещи высшего порядка, в первую очередь - у них есть некоторые данные, но они также выполняют множество операций, и довольно много того, что составляет хороший ООП-проект, сводится к тому, что «объекты должныобычно действуют как комбинаторы, а не структуры данных ".

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

...