Turn on lambda block scanner in clojure

I just started reading Let over lambda, and I thought that I would try to write a version of the clojure block scanner in the closing chapter.

I have the following:

(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"))

It works, I think, but I would like to know what I did right and what I could do better.

+3
source share
1 answer

I would not use ref-set, but alterbecause you do not reset the state to a completely new value, but update it to a new value, which is obtained from the old one.

(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))))

Then there is no need to use refs, since you do not need to coordinate the changes. Here the atom is better suited, as it can be changed without any STM ceremony.

(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))))

Next, I would get rid of the imperative style.

  • , : , . .
  • , - . . ( , , , .)
  • . , .
(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)))))
+8

Source: https://habr.com/ru/post/1755927/


All Articles