在递归函数完成后deref一个原子

时间:2017-03-12 14:39:36

标签: recursion clojure atomicity

我有一个原子freq-seq,我在递归函数mine-freq-seqs内更新,这是保存计算结果的值。我有另一个函数freq-seq来启动mine-freq-seqs,当(ns freq-seq-enum) (def fs (atom #{})) (defn locally-frequents [sdb min-sup] (let [uniq-sdb (map (comp frequencies set) sdb) freqs (apply merge-with + uniq-sdb)] (->> freqs (filter #(<= min-sup (second %))) (map #(vector (str (first %)) (second %)))))) (defn project-sdb [sdb prefix] (if (empty? prefix) sdb (into [] (->> sdb (filter #(re-find (re-pattern (str (last prefix))) %)) (map #(subs % (inc (.indexOf % (str (last prefix)))))) (remove empty?))))) (defn freq-seq [sdb prefix prefix-support min-sup frequent-seqs] (if ((complement empty?) prefix) (swap! fs conj [prefix prefix-support])) (let [lf (locally-frequents sdb min-sup)] (if (empty? lf) nil (for [[item sup] lf] (freq-seq (project-sdb sdb (str prefix item)) (str prefix item) sup min-sup @fs))))) (defn mine-freq-seqs [sdb min-sup] (freq-seq sdb "" 0 min-sup @fs)) 完成时,我希望收到所述原子的最后一个值。所以我想我会这样做

(mine-freq-seqs ["CAABC" "ABCB" "CABC" "ABBCA"] 2)

先运行

(deref fs)

然后解除原子 #{["B" 4] ["BC" 4] ["AB" 4] ["CA" 3] ["CAC" 2] ["AC" 4] ["ABC" 4] ["CAB" 2] ["A" 4] ["CABC" 2] ["ABB" 2] ["CC" 2] ["CB" 3] ["C" 4] ["BB" 2] ["CBC" 2] ["AA" 2]}

产量

(doall (mine-freq-seqs ["CAABC" "ABCB" "CABC" "ABBCA"] 2) (deref fs))

然而#{}

只提供freq-seq

我想要的是让fs递归完成然后获得原子mine-freq-seq的值。所以我可以调用(array.product(array) - array.zip(array)).each do |(k, l)| ... end 并在REPL中返回我的结果,而不必在那里手动deref它。

2 个答案:

答案 0 :(得分:2)

首先是一些没有原子的替代代码然后看看为什么你得到空的回报。

一个更紧凑的版本,其中字符串中的序列是使用reduce而不是使用regex和substr的递归来派生的。

然后只对这些结果做一个频率。

(defn local-seqs
  [s]
  (->> s
       (reduce (fn [acc a] (into acc (map #(conj % a) acc))) #{[]})
       (map #(apply str %))
       (remove empty?)))

(defn freq-seqs
  [sdb min-sup]
  (->> (mapcat local-seqs sdb)
       frequencies
       (filter #(>= (second %) min-sup))
       set))

这就是整个事情! 我没有涉及原子,因为我没有看到需要,但如果你愿意的话,如果是freq-seqs则最后添加它。

对于您的原始问题:您看到的回报为什么?

您正在使用2个参数调用doall,这是您的通话和收集的结果。 doall是一个函数而不是宏,因此deref立即执行。

(defn doall 
   ;; <snip>
  ([n coll]        ;; you have passed #{} as coll 
   (dorun n coll)  ;; and this line evals to nil
   coll)           ;; and #{} is returned

您已将结果作为n arg传递,将空集作为coll传递(来自(deref fs)

现在,当doall调用dorun时,会遇到以下情况:

(defn dorun
 ;; <snip>  
([n coll]
 (when (and (seq coll) (pos? n)) ;; coll is #{} so the seq is falesy
   (recur (dec n) (next coll)))) ;; and a nil is returned

由于fs的空集是第二个arg(coll)而and是一个宏,它在(seq coll)上是假的,返回nil然后doall返回空集这是它的第二个arg。

最后的说明:

所以这是有效的,为什么你的失败。至于如何使你的工作,我尝试修复上面的调用:

(do (doall (mine-freq-seqs ["CAABC" "ABCB" "CABC" "ABBCA"] 2))
    (deref fs))

这更接近于工作,但随着你的过程中的重复,它只会强制eval一层深。因此你可以将doall更深入地推入你的funcs,但我提出了一个完全不同的内部结构,所以如果你真的需要那个结构,我会把剩下的留给你。

答案 1 :(得分:1)

我稍微更改了一下以删除所有惰性位(这在repl中无声地发生,但是当它在repl之外更改时可能会令人困惑)。请注意vecmapvdoall的更改。至少现在我得到了你的结果:

(def fs (atom #{}))

(defn locally-frequents
  [sdb min-sup]
  (let [uniq-sdb (map (comp frequencies set) sdb)
        freqs    (apply merge-with + uniq-sdb)]
    (->> freqs
      (filter #(<= min-sup (second %)))
      (mapv #(vector (str (first %)) (second %))))))


(defn project-sdb
  [sdb prefix]
  (if (empty? prefix)
    sdb
    (into [] (->> sdb
               (filter #(re-find (re-pattern (str (last prefix))) %))
               (map #(subs % (inc (.indexOf % (str (last prefix))))))
               (remove empty?)))))


(defn freq-seq
  [sdb prefix prefix-support min-sup frequent-seqs]
  (if ((complement empty?) prefix) (swap! fs conj [prefix prefix-support]))
  (let [lf (locally-frequents sdb min-sup)]
    (if (empty? lf)
      nil
      (vec (for [[item sup] lf] (freq-seq (project-sdb sdb (str prefix item)) (str prefix item) sup min-sup @fs))))))

(defn mine-freq-seqs
  [sdb min-sup]
  (freq-seq sdb "" 0 min-sup @fs))

(doall (mine-freq-seqs ["CAABC" "ABCB" "CABC" "ABBCA"] 2))

(deref fs) => #{["B" 4] ["BC" 4] ["AB" 4] ["CA" 3] 
                ["CAC" 2] ["AC" 4] ["ABC" 4] ["CAB" 2] 
                ["A" 4] ["CABC" 2] ["ABB" 2] ["CC" 2] ["CB" 3] 
                ["C" 4] ["BB" 2] ["CBC" 2] ["AA" 2]}

我仍然不确定目标是什么,或者如何/为什么你会得到像#CABC&#34;

这样的条目。