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

deref an atom after recursive function completes

我有一个原子 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)

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

我稍微更改了它以删除所有惰性位(这在 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]}

我仍然不确定目标是什么,或者 how/why 你会得到像 "CABC".

这样的条目

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

一个更紧凑的版本,其中字符串中的序列是使用 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 在最后添加它。

对于您最初的问题:为什么您看到 return?

您正在使用 2 个参数调用 doall,即您的调用结果和一个集合。 doall 是函数而不是宏,因此会立即执行取消引用。

(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)、return nil 和然后做所有 returns 作为第二个参数的空集。

最后的注释:

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

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

这更接近工作,但由于您的过程中的回避,它只会迫使 eval 深入一层。所以你可以把 doall 推到你的 funcs 更深的地方,但我提出了一个完全不同的内部结构,所以如果你真的需要那个结构,我会把剩下的留给你。