【问题标题】:Clojure reducers fold not calling combine function as expectedClojure reducers 折叠未按预期调用组合函数
【发布时间】:2016-02-01 16:04:30
【问题描述】:

我正在尝试使用 clojure reducers 库,但对于何时将组合函数作为 reducers/fold 函数的一部分调用,我有点困惑。为了查看什么时候被调用,我创建了以下示例:

(def input (range 1 100))

(defn combine-f
  ([]
    (println "identity-combine")
    0)
  ([left right]
    (println (str "combine " left " "  right))
    (max (reduce max 0 left)
         (reduce max 0 right))))

(defn reduce-f
  ([]
    (println "identity-reduce")
    0)
  ([result input]
    (println (str "reduce " result " "  input))
    (max result input)))

(clojure.core.reducers/fold 10 combine-f reduce-f input)

;prints
identity-combine
reduce 0 1
reduce 1 2
reduce 2 3
reduce 3 4
.
.
.
reduce 98 99

我期望当 fold 执行时,输入将被分成大约 10 大小的组,每个组使用 reduce-f 减少,然后使用 combine-f 组合。但是运行上面的代码,似乎 combine 函数只作为一个身份被调用一次,并且整个输入使用 reduce-f 减少。谁能解释我为什么会看到这种行为?

谢谢,

马特。

【问题讨论】:

    标签: clojure parallel-processing


    【解决方案1】:

    很遗憾,range 目前无法并行实现。 It seems there are foldable implementations around as an enhancement ticket, but I can't seem to find right now why they haven't been accepted. 照原样,folds 在 range 上总是会像直接的 reduce 一样继续进行,除了对 combine 运算符的身份调用。作为比较,向量提供随机访问,因此是可折叠的:

    (def input (vec (range 1 50)))
    
    (defn combine-f
      ([]
        (println "identity-combine")
        Long/MIN_VALUE)
      ([left right]
        (println (str "combine " left " "  right))
        (max left right)))
    
    (defn reduce-f
      ([]
        (println "identity-reduce")
        Long/MIN_VALUE)
      ([result input]
        (println (str "reduce " result " "  input))
        (max result input)))
    
    (clojure.core.reducers/fold 10 combine-f reduce-f input)
    

    带输出:

    identity-combineidentity-combineidentity-combine
    
    
    reduce -9223372036854775808 1
    
    reduce -9223372036854775808 25reduce -9223372036854775808 19
    
    
    reduce -9223372036854775808 13reduce 25 26
    
    
    reduce 26 27
    reduce 1 2
    
    reduce 27 28
    
    reduce 28 29
    
    reduce 29 30
    
    
    
    reduce 2 3
    reduce 19 20
    
    reduce 3 4
    
    identity-combinereduce 4 5
    
    reduce 5 6reduce 13 14
    
    
    reduce 14 15
    
    
    reduce 20 21identity-combine
    
    reduce 21 22
    
    reduce 15 16
    
    
    
    reduce -9223372036854775808 31
    
    reduce 22 23reduce 16 17reduce -9223372036854775808 7
    
    
    reduce 7 8
    
    
    reduce 8 9
    
    reduce 23 24
    
    reduce 31 32
    reduce 17 18
    
    
    reduce 9 10
    
    reduce 10 11
    
    
    reduce 11 12
    
    identity-combine
    reduce 32 33
    
    combine 18 24
    
    
    combine 6 12identity-combine
    reduce -9223372036854775808 37
    
    
    reduce 33 34
    
    reduce 37 38reduce -9223372036854775808 43
    combine 12 24
    
    
    
    reduce 43 44reduce 34 35reduce 38 39
    
    reduce 44 45
    
    reduce 35 36
    
    
    reduce 45 46
    reduce 39 40
    
    reduce 46 47
    combine 30 36
    
    reduce 47 48
    
    
    
    reduce 48 49
    
    reduce 40 41
    
    reduce 41 42
    
    combine 42 49
    
    combine 36 49
    combine 24 49
    

    由于*out* 的非序列化访问,您可能会注意到它更加混乱。
    (我需要稍微改变combine-f,因为它正在尝试并在一个长的时间内未能reduce。切换到Long/MIN_VALUE 不会对 this 示例产生太大影响,但它是max 很长,所以我想为什么不呢?)。

    【讨论】:

    • 谢谢。我没有考虑过这个范围不会自己弃牌。是否有任何直接的方法可以确定任何 seq/collection 是否可折叠?我看不到可折叠的?不幸的是,API 中的函数。
    • 我不这么认为。有(satisfies? clojure.core.reducers/CollFold x),但它并不是非常有用。 reducers.core namespace extends it over Object,这是我怀疑 range 实现的地方。看起来主要是 IPersistentVector 和 PersistentHashmap 做的。
    猜你喜欢
    • 2020-01-14
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 2014-03-28
    相关资源
    最近更新 更多