问下clojure reducer下的fold怎么用

clojure-china好像上不去了,我也不知道他们在搞什么东西

问题

在 七周七并发 函数式并行 --用折叠实现词频统计这一小节里,定义了一个这样的函数

(defn parallel-frequencies [coll]
  (r/fold
   (partial merge-with +)
   (fn [counts x] (assoc counts x (inc (get counts x 0))))
   coll))

这里fold使用的第二个函数让我感到很奇怪,一般使用到归约(reduce)实现频率统计是这样写的

(fn [nums]
  (reduce (fn [r x]
            (assoc r x (inc (get r x 0)))) 
   {} nums))

倒数第二个参数{}作为保存结果返回 ,一般你得先声明好参数,不然会报错
而fold直接放函数进去了,我不知道这是什么原理

好久没用 Clojure 了,尝试 debug 下

(defn parallel-frequencies [coll]
  (r/fold
   (partial merge-with +)
   (fn [counts x]
     (prn counts)
     (assoc counts x (inc (get counts x 0))))
   coll))

(parallel-frequencies [:a :b :c :a])
nil
{:a 1}
{:a 1, :b 1}
{:a 1, :b 1, :c 1}
{:a 2, :b 1, :c 1}

再去看 fold 定义,最后定位到这里

(defn- foldvec
  [v n combinef reducef]
  (cond
   (empty? v) (combinef)
   (<= (count v) n) (reduce reducef (combinef) v)
   :else
   (let [split (quot (count v) 2)
         v1 (subvec v 0 split)
         v2 (subvec v split (count v))
         fc (fn [child] #(foldvec child n combinef reducef))]
     (fjinvoke
      #(let [f1 (fc v1)
             t2 (fjtask (fc v2))]
         (fjfork t2)
         (combinef (f1) (fjjoin t2)))))))

如果没提供初始值,就用 (combinef)

((partial merge-with +))  ;; => nil

这样应该就能解答楼主问题。 记得这应该是 Clojure 1.7 在引入 Transducers 时修改的,方便处理初始状态。

PS. 对 Clojure 感兴趣可以加

Telegram:https://t.me/clojurists 这个被墙了,国内资料太少了

科学上网是学好编程的第一步呀,可参考:

白嫖使我快乐