【问题标题】:Clojure reduced functionClojure 简化功能
【发布时间】:2015-12-22 17:34:48
【问题描述】:

我知道有 reduced 函数可以终止这样一个无限的事情,但我很好奇为什么在第二个版本中(range 没有 arg)它不会在达到 150 时终止减少?

user=> (reduce (fn [a v] (if (< a 100) (+ a v) a)) (range 2000))
105
user=> (reduce (fn [a v] (if (< a 100) (+ a v) a)) (range))

【问题讨论】:

    标签: clojure reduce


    【解决方案1】:

    因为reduce对序列(range)中的每一个元素都应用了函数,所以(range)就完全实现了。

     (range) 
    

    产生一个无限序列,并且

     (fn [a v] (if (< a 100) (+ a v) a))
    

    不会停止循环,它会应用于每个元素。

    在 REPL 上执行

     (reduce (fn [a v] (if (< a 100) (+ a v) a)) (range))
    

    表示我们很早就想获取并打印结果,因此 REPL 挂起。

    【讨论】:

    • 那么这是否意味着if 对处理没有影响?每次reduce将函数应用于序列中的下一个元素时,if不会检查a
    【解决方案2】:

    正如你提到的,对于那些后来在谷歌上搜索的人来说,减少了。归约函数确实有能力显式声明归约的最终答案,并保证不会通过返回调用 (reduced the-final-answer) 的结果来消耗进一步的输入

    user> (reduce (fn [a v] 
                    (if (< a 100) 
                      (+ a v) 
                      (reduced a))) 
                   (range))
    105
    

    在这种情况下,当新收集的结果超过 100 时,下一次迭代将停止缩减,而不是将其值贡献给答案。这确实消耗了输入流中未包含在结果中的一个额外值。

    user> (reduce (fn [a v]
                    (let [res (+ a v)]
                      (if (< res 100)
                        res
                        (reduced res))))
                  (range))
    105
    

    一旦达到阈值,这就会完成减少,并且不会消耗惰性(和无限)集合中的任何额外值。

    【讨论】:

      猜你喜欢
      • 2017-11-29
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 2014-11-29
      • 2014-10-30
      • 2018-10-29
      • 1970-01-01
      相关资源
      最近更新 更多