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