我理解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)
Run Code Online (Sandbox Code Playgroud)
然而,哪一个更惯用的clojure?这种方式或其他方式有什么不同吗?从我的(有限的)性能测试来看,似乎reduce更快一些.
Mic*_*zyk 119
reduce并且apply当然只对于需要在变量arity情况下查看所有参数的关联函数而言(仅就返回的最终结果而言)是等效的.当它们在结果方面相当时,我会说这apply总是完全惯用的,而reduce在很多常见的情况下,它可能是相同的 - 并且可能会在很短的时间内完成.以下是我相信这一点的理由.
+本身是reduce针对变量案例(超过2个参数)实现的.事实上,对于任何变量,关联函数来说,这似乎是一种非常明智的"默认"方式:reduce有可能执行一些优化以加快速度 - 可能通过internal-reduce最近在主人身上禁用的1.2新颖性,但是希望将来能够重新引入 - 在vararg案例中,在每个可能从中受益的函数中复制将是愚蠢的.在这种常见情况下,apply只会增加一点开销.(注意没什么好担心的.)
另一方面,复杂的功能可能会利用一些不够通用的优化机会reduce; 然后apply会让你利用那些reduce可能实际上减慢你的速度.在实践中出现的后一种情况的一个很好的例子是str:它在StringBuilder内部使用,并且将从使用apply而不是使用中获益reduce.
所以,我apply怀疑时会说使用; 如果你碰巧知道它不会给你带来任何东西reduce(并且这不太可能很快改变),reduce如果你愿意,可以随意使用来减少这种微小的不必要的开销.
Dav*_*ala 49
对于看这个答案的新手,
要小心,他们不一样:
(apply hash-map [:a 5 :b 6])
;= {:a 5, :b 6}
(reduce hash-map [:a 5 :b 6])
;= {{{:a 5} :b} 6}
Run Code Online (Sandbox Code Playgroud)
drc*_*ode 20
意见各不相同 - 在更大的Lisp世界中,reduce绝对被认为是更惯用的.首先,已经讨论过可变问题.此外,一些Common Lisp编译器在apply应用于非常长的列表时实际上会失败,因为它们处理参数列表的方式.
然而,在我的圈子中的Clojurists中,apply在这种情况下使用似乎更常见.我发现它更容易理解并且也更喜欢它.
我通常发现自己更喜欢使用reduce来处理任何类型的集合 - 它表现良好,并且通常是非常有用的功能.
我将使用apply的主要原因是,如果参数在不同的位置意味着不同的东西,或者如果你有一些初始参数但想要从集合中获取其余参数,例如
(apply + 1 2 other-number-list)
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,我更喜欢,reduce因为它更具可读性:当我阅读时
(reduce + some-numbers)
Run Code Online (Sandbox Code Playgroud)
我立即知道你正在将一个序列变成一个值.
随着apply我要考虑的是被应用于其功能:"啊,它的+功能,所以我得到...单号".略显简单明了.
当使用像+这样的简单函数时,使用哪一个并不重要.
一般来说,这个想法reduce是一个累积操作.您将当前累积值和一个新值呈现给累积函数.函数的结果是下一次迭代的累积值.所以,你的迭代看起来像:
cum-val[i+1] = F( cum-val[i], input-val[i] ) ; please forgive the java-like syntax!
Run Code Online (Sandbox Code Playgroud)
对于apply,这个想法是你试图调用一个期望一些标量参数的函数,但它们目前在一个集合中,需要被拔出.所以,而不是说:
vals = [ val1 val2 val3 ]
(some-fn (vals 0) (vals 1) (vals 2))
Run Code Online (Sandbox Code Playgroud)
我们可以说:
(apply some-fn vals)
Run Code Online (Sandbox Code Playgroud)
它被转换为相当于:
(some-fn val1 val2 val3)
Run Code Online (Sandbox Code Playgroud)
因此,使用"apply"就像序列周围的"删除括号".
apply 的美妙之处在于给定函数(在本例中为 +)可以应用于由预先挂起的中间参数和结尾集合形成的参数列表。Reduce 是一个抽象,用于处理集合项,为每个集合项应用函数,并且不适用于变量 args 的情况。
(apply + 1 2 3 [3 4])
=> 13
(reduce + 1 2 3 [3 4])
ArityException Wrong number of args (5) passed to: core/reduce clojure.lang.AFn.throwArity (AFn.java:429)
Run Code Online (Sandbox Code Playgroud)