递归函数完成后取消引用原子
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 之外更改时可能会造成混淆)。请注意 vec
、mapv
和 doall
的变化。至少现在我得到了你的结果:
(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 更深的地方,但我提出了一个完全不同的内部结构,所以如果你真的需要那个结构,我会把剩下的留给你。
我有一个原子 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 之外更改时可能会造成混淆)。请注意 vec
、mapv
和 doall
的变化。至少现在我得到了你的结果:
(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 更深的地方,但我提出了一个完全不同的内部结构,所以如果你真的需要那个结构,我会把剩下的留给你。