recursion - 递归函数完成后取消引用原子

标签 recursion clojure atomic

我有一个原子 fs,我正在递归函数 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)

然后解引用原子 (取消引用 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 并将结果返回到 REPL 中,而不必在那里手动取消引用。

最佳答案

首先是一些不带原子的备用代码,然后看看为什么会得到空返回。

一个更紧凑的版本,其中字符串中的序列是通过归约而不是使用正则表达式和 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))

这就是全部! 我没有涉及原子,因为我没有看到需要,但如果您愿意,可以在 if freq-seqs 最后添加它。

对于您最初的问题:为什么您会看到返回?

您正在调用doall有 2 个参数,即调用结果和集合。 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) 上它将是 falsey ,返回 nil,然后 doall 返回空集,即第二个参数。

最后一点:

所以这就是有效的方法,也是你失败的原因。至于如何让你的工作正常工作,修复上面的调用我尝试过:

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

这更接近工作,但由于流程中的回避,它只会迫使评估深入一层。因此,您可以将 doall 更深地插入您的函数中,但我提出了一个完全不同的内部结构,因此如果您确实需要该结构,我将把剩下的留给您。

关于recursion - 递归函数完成后取消引用原子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42748717/

相关文章:

recursion - 如何反转列表?

c++ - 危害指标的内存排序

c++ - 在没有互斥锁的情况下并发追加到列表尾部

python - 递归选择排序以返回python中的降序列表

algorithm - 阶乘新算法的递归方程

java - 在 Java 对象树上创建的 Clojure zipper 可以在 zip-filter 中工作吗?

list - Clojure:移动列表中的项目

c++ - 关键字 "shared"是否可以防止竞争条件?

c++ - 使用迭代器的递归调用崩溃

clojure - 如何在Clojure中使用expt函数?