代码之家  ›  专栏  ›  技术社区  ›  dbyrne

Clojure:减少vs.应用

  •  118
  • dbyrne  · 技术社区  · 14 年前

    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?这有什么不同吗?从我的(有限的)性能测试来看,似乎 减少 速度快一点。

    9 回复  |  直到 14 年前
        1
  •  128
  •   Michał Marczyk    14 年前

    reduce apply 当然,对于需要在变量arity情况下查看其所有参数的关联函数,它们只是等价的(就返回的最终结果而言)。当它们在结果上等价时,我会这么说 应用 总是非常地道,而 减少 在很多常见的情况下,这一点是相当的——而且可能会在眨眼之间剃掉一小部分。下面是我相信这一点的理由。

    + 在以下方面实施 减少 对于变量arity情况(多于2个参数)。事实上,这似乎是一个非常明智的“默认”方式去为任何变量算术,联想函数: 减少 有可能执行一些优化来加快速度--也许是通过 internal-reduce 只会增加一点开销(注意:没什么好担心的。)

    另一方面,一个复杂的函数可能会利用一些优化机会,这些优化机会不够一般,无法内置到函数中 减少 应用 会让你在 减少 可能会让你慢下来。后一种情况在实践中发生的一个很好的例子是 str :它使用 StringBuilder 应用 而不是 .

    应用 有疑问时;如果你碰巧知道它不会给你买任何东西 减少 (而且这不太可能很快改变),请随意使用 如果你愿意的话,把不必要的小开销剃掉。

        2
  •  55
  •   David Rz Ayala    11 年前

    对于新手来说,

    (apply hash-map [:a 5 :b 6])
    ;= {:a 5, :b 6}
    (reduce hash-map [:a 5 :b 6])
    ;= {{{:a 5} :b} 6}
    
        3
  •  22
  •   G__    14 年前

    在这种情况下没有区别,因为+是一种特殊情况,可以应用于任意数量的参数。Reduce是一种将需要固定数量的参数(2)的函数应用于任意长的参数列表的方法。

        4
  •  22
  •   Brad Koch Daniel Wright    10 年前

    不同的观点-在更大的Lisp世界, reduce 绝对被认为更地道。首先,是已经讨论过的可变问题。此外,一些常见的Lisp编译器在 apply 应用于非常长的列表,因为它们是如何处理参数列表的。

    但在我圈子里的法学家中 在这种情况下似乎更常见。我发现它更容易摸索,也更喜欢它。

        5
  •  11
  •   mikera    13 年前

    通常,我发现自己在处理任何类型的集合时都更喜欢reduce—它执行得很好,总体上是一个非常有用的函数。

    (apply + 1 2 other-number-list)
    
        6
  •  10
  •   mascip    10 年前

    在这种情况下,我更喜欢 reduce 因为它比 :当我阅读时

    (reduce + some-numbers)
    

    我马上就知道你在把一个序列变成一个值。

    apply 我必须考虑应用哪个函数:“啊,这是 +

        7
  •  8
  •   Alan Thompson    6 年前

    当使用像+这样的简单函数时,使用哪一个并不重要。

    总的来说,我们的想法是 reduce

    cum-val[i+1] = F( cum-val[i], input-val[i] )    ; please forgive the java-like syntax!
    

    对于apply,您的想法是试图调用一个需要许多标量参数的函数,但它们当前在一个集合中,需要被拉出。所以,与其说:

    vals = [ val1 val2 val3 ]
    (some-fn (vals 0) (vals 1) (vals 2))
    

    我们可以说:

    (apply some-fn vals)
    

    转换为:

    (some-fn val1 val2 val3)
    

    因此,使用“apply”就像在序列周围“去掉括号”。

        8
  •  4
  •   rohit    10 年前

    关于这个话题有点晚了,但我在读了这个例子之后做了一个简单的实验。这是我的repl的结果,我只是无法从响应中推断出任何东西,但似乎在reduce和apply之间存在某种缓存。

    user=> (time (reduce + (range 1e3)))
    "Elapsed time: 5.543 msecs"
    499500
    user=> (time (apply + (range 1e3))) 
    "Elapsed time: 5.263 msecs"
    499500
    user=> (time (apply + (range 1e4)))
    "Elapsed time: 19.721 msecs"
    49995000
    user=> (time (reduce + (range 1e4)))
    "Elapsed time: 1.409 msecs"
    49995000
    user=> (time (reduce + (range 1e5)))
    "Elapsed time: 17.524 msecs"
    4999950000
    user=> (time (apply + (range 1e5)))
    "Elapsed time: 11.548 msecs"
    4999950000
    

        9
  •  3
  •   Ira    7 年前

    apply is given函数的优点是(+在本例中)可以应用于由带有结束集合的预挂起的中间参数形成的参数列表。Reduce是处理集合项的抽象,为每个集合项应用函数,不适用于变量args case。

    (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)