clojure-从atom重构为不可变

clojure-从atom重构为不可变,clojure,Clojure,我有一个嵌套的reduce函数,我使用一个名为counter的原子在每次满足条件时递增一个计数 (defrecord TreeNode [val left right]) (defn build-tree [node xs] (let [counter (atom 1)] (reduce (fn [t x] (reduce (fn [t l] (if-not (= (:val l) -1)

我有一个嵌套的reduce函数,我使用一个名为counter的原子在每次满足条件时递增一个计数

(defrecord TreeNode [val left right])

(defn build-tree [node xs]
  (let [counter (atom 1)]
   (reduce (fn [t x]
             (reduce (fn [t l]
                       (if-not (= (:val l) -1)
                         (let [next-branch (nth xs @counter)]
                           (swap! counter inc)
                           ;; do stuff
                           ) t)
                       )t (map-indexed
                           (fn [idx itm]
                             (let [side (if (= 0 idx) :left :right)]
                               {:side side :index idx :val itm})) x))) node xs)))

我不喜欢在函数中使用可变的ref。有没有一种方法可以在不使用ref的情况下实现相同的行为?

单引号在[(inc counter')t']
counter'
中是什么意思,
t'
是绑定名称,遵循命名的数学约定,例如
x
x'
等。其中
表示“下一个值”依次
;; for starters, we can pass the counter through each reduce
(defn build-tree [node xs]
  (let [[counter tree] (reduce (fn [[counter tree] x]
                                 (reduce (fn [[counter' t] l]
                                           (if-not (= (:val l) -1)
                                             (let [next-branch (nth xs counter)
                                                   ... ...
                                                   t' ...]
                                               [(inc counter') t'])
                                             [counter' t])
                                           [counter t]
                                           (map-indexed
                                            (fn [idx itm]
                                              (let [side (if (= 0 idx) :left :right)]
                                                {:side side :index idx :val itm}))
                                            x))))
                               [0 node]
                               xs)]))

;; the code becomes much clearer with apropriate let bindings
(defn build-tree
  [node xs]
  ;; the optional name arg to an anonymous function makes stack traces much easier to read
  (let [process-branch (fn process-branch [[counter t] l]
                         (if-not (= (:val l) -1)
                           (let [next-branch (nth xs counter)
                                 ... ...
                                 t' ...]
                             [(inc counter) t'])
                           [counter t]))
        mark-branch (fn mark-branch [x]
                      (map-indexed
                       (fn [idx itm]
                         (let [side (if (= 0 idx) :left :right)]
                           {:side side :index idx :val itm}))
                       x))
        [counter tree] (reduce (fn [[counter tree] x]
                                 (reduce process-branch
                                         [counter t]
                                         (mark-branch x)))
                               [0 node]
                               xs)]
    tree))