我不會使用ref-set
而是alter
,因爲您不會將狀態重置爲全新值,而是會將其更新爲從舊值中獲取的新值。
(defn block-scanner
[trigger-string]
(let [curr (ref trigger-string)
trig trigger-string]
(fn [data]
(doseq [c data]
(when (seq @curr)
(dosync
(alter curr
#(if (-> % first (= c))
(rest %)
trig)))))
(empty? @curr))))
然後沒有必要使用refs,因爲您不必協調更改。這裏原子更合適,因爲它可以在沒有STM儀式的情況下進行更改。
(defn block-scanner
[trigger-string]
(let [curr (atom trigger-string)
trig trigger-string]
(fn [data]
(doseq [c data]
(when (seq @curr)
(swap! curr
#(if (-> % first (= c))
(rest %)
trig))))
(empty? @curr))))
接下來我將擺脫勢在必行的風格。
- 它比它應該做的更多:它遍歷所有數據 - 即使我們已經找到了匹配項。我們應該儘早停止。
- 它不是線程安全的,因爲我們多次訪問原子 - 它可能會在兩者之間變化。所以我們只能碰觸一次原子。 (雖然在這種情況下這可能不是很有趣,但是把它作爲一種習慣很好)。
- 它很醜。當我們得出結果時,我們可以在功能上完成所有工作並保存狀態。
(defn block-scanner
[trigger-string]
(let [state (atom trigger-string)
advance (fn [trigger d]
(when trigger
(condp = d
(first trigger) (next trigger)
; This is maybe a bug in the book. The book code
; matches "foojihad", but not "jijihad".
(first trigger-string) (next trigger-string)
trigger-string)))
update (fn [trigger data]
(if-let [data (seq data)]
(when-let [trigger (advance trigger (first data))]
(recur trigger (rest data)))
trigger))]
(fn [data]
(nil? (swap! state update data)))))
哇,好東西,現在我必須消化這一點,並理解它。謝謝。 – 2010-07-22 13:53:38