我有一个原子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它。
答案 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之外更改时可能会令人困惑)。请注意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]}
我仍然不确定目标是什么,或者如何/为什么你会得到像#CABC&#34;
这样的条目。