Clojure: уменьшите по сравнению с, применяются

Я понимаю концептуальное различие между reduce и apply:

(reduce + (list 1 2 3 4 5))
; translates to: (+ (+ (+ (+ 1 2) 3) 4) 5)

(apply + (list 1 2 3 4 5))
; translates to: (+ 1 2 3 4 5)

Однако, какой является большим количеством идиоматического clojure? Это имеет много значения так или иначе? От моего (ограниченного) тестирования производительности это кажется reduce немного быстрее.

123
задан dbyrne 30 June 2010 в 21:04
поделиться

4 ответа

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

+ сам по себе реализован в терминах reduce для случая переменной арности (более 2 аргументов).В самом деле, это кажется чрезвычайно разумным способом «по умолчанию» для любой ассоциативной функции переменной арности: reduce имеет потенциал для выполнения некоторых оптимизаций для ускорения работы - возможно, с помощью чего-то вроде internal-reduce , новинка 1.2, недавно отключенная в master, но, надеюсь, будет повторно представлена ​​в будущем - что было бы глупо повторять во всех функциях, которые могли бы получить от них пользу в случае vararg. В таких общих случаях apply просто добавит немного накладных расходов. (Обратите внимание, что это не повод для беспокойства.)

С другой стороны, сложная функция может использовать преимущества некоторых возможностей оптимизации, которые недостаточно общие, чтобы быть встроенными в reduce ; тогда apply позволит вам воспользоваться ими, в то время как reduce может действительно замедлить вас. Хороший пример последнего сценария, встречающегося на практике, - это str : он использует StringBuilder внутри и значительно выиграет от использования apply , а не уменьшить .

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

119
ответ дан 24 November 2019 в 01:16
поделиться

Мнения различаются - В большом мире Лиспа reduce определенно считается более идиоматическим. Во-первых, уже обсуждались различные вопросы. Кроме того, некоторые компиляторы Common Lisp фактически не работают, когда apply применяется к очень длинным спискам из-за того, как они обрабатывают списки аргументов.

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

20
ответ дан 24 November 2019 в 01:16
поделиться

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

19
ответ дан 24 November 2019 в 01:16
поделиться

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

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

(apply + 1 2 other-number-list)
9
ответ дан 24 November 2019 в 01:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: