我刚刚开始阅读Let over lambda,我想我会尝试在闭包章节中编写块扫描程序的clojure版本。
到目前为止,我有以下内容:
(defn block-scanner [trigger-string]
(let [curr (ref trigger-string) trig trigger-string]
(fn [data]
(doseq [c data]
(if (not (empty? @curr))
(dosync(ref-set curr
(if (= (first @curr) c)
(rest @curr)
trig)))))
(empty? @curr))))
(def sc (block-scanner "jihad"))
我认为这是有效的,但我想知道我做得对,我能做得更好。
答案 0 :(得分:8)
我不会使用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))))
然后没有必要使用引用,因为您不必协调更改。在这里,原子更适合,因为它可以在没有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)))))