0

我使用loop recur一些相当复杂的逻辑进行递归。事实证明,我应该在两个分支中做相同的事情,这都应该导致递归。由于 recur 的限制,我不相信我可以使用函数将其抽象出来,所以我怎么能这样做并且没有重复的代码。我必须使用宏吗?

代码如下,重复代码用 REPEATED CODE HERE 高亮显示

(defn overlapping-sampler [n-samples]
  (let [...]
    (loop [samples [] cache (zipmap boxes []) n-samples n-samples]
      (cond
        (zero? n-samples)
        samples

        :else
        (let [box (categorical boxes volumes)
              cache-item (peek (cache box))]
          (if (nil? cache-item)
              ; REPEATED CODE HERE
              (let [sample (interval-sample (:internals box))
                    all-boxes (map #(apply (:formula %) sample) boxes)
                    pos-dominant (max-pred-index true? all-boxes)
                    pos-box (max-pred-index #(= box %) boxes)]
                    (if (= pos-dominant pos-box)
                        (recur (conj samples sample) cache (dec n-samples))
                        (recur samples
                               (update-in cache [(nth boxes pos-dominant)]
                                          #(conj % {:from box :sample sample}))
                               n-samples)))

              ; Otherwise with prob p=ratio of overlapping region/box, take sample
              (if (flip (/ (volume (overlap box (:from cache-item))) (volume box)))
                  (recur (conj samples (:sample cache-item)) ; I should take the sample
                         (update-in cache [box]
                                    #(pop %))
                         (dec n-samples))

                  (let [sample (gen-until #(interval-sample (:internals box))
                                    #(and (apply (:formula box) %)
                                          (not (apply (:formula (:from cache-item)) %))))
                        ;REPEATED CODE HERE
                        all-boxes (map #(apply (:formula %) sample) boxes)
                        pos-dominant (max-pred-index true? all-boxes)
                        pos-box (max-pred-index #(= box %) boxes)]
                        (if (= pos-dominant pos-box)
                            (recur (conj samples sample) cache (dec n-samples))
                            (recur samples
                                   (update-in cache [(nth boxes pos-dominant)]
                                              #(conj % {:from box :sample sample}))
                                   n-samples))))))))))
4

2 回答 2

1

使用本地函数:

(defn overlapping-sampler [n-samples]
  (let [fun (fn [sample samples]
              (let  [all-boxes (map #(apply (:formula %) sample) boxes)
                     pos-dominant (max-pred-index true? all-boxes)
                     pos-box (max-pred-index #(= box %) boxes)]
                (if (= pos-dominant pos-box)
                  [(conj samples sample) cache (dec n-samples)]
                  [samples
                   (update-in cache [(nth boxes pos-dominant)]
                              #(conj % {:from box :sample sample}))
                 n-samples])))]
    (loop [[samples cache n-samples] [[] (zipmap boxes []) n-samples]]
      (cond
        (zero? n-samples)
        samples

        :else
        (let [box (categorical boxes volumes)
              cache-item (peek (cache box))]
          (if (nil? cache-item)
              ; REPEATED CODE HERE
            (let [sample (interval-sample (:internals box))]
              (recur (fun sample) samples))
              ; Otherwise with prob p=ratio of overlapping region/box, take sample
              (if (flip (/ (volume (overlap box (:from cache-item))) (volume box)))
                  (recur [(conj samples (:sample cache-item)) ; I should take the sample
                         (update-in cache [box]
                                    #(pop %))
                         (dec n-samples)])

                  (let [sample (gen-until #(interval-sample (:internals box))
                                    #(and (apply (:formula box) %)
                                          (not (apply (:formula (:from cache-item)) %))))]
                    (recur (fun sample) samples)))))))))
于 2013-07-26T08:45:53.940 回答
0

也许重写为

(let [cache-item ...]
  (if (and (nil? cache-item) (flip ...))
    (recur ...)
    (let [sample (if (nil? cache-item)
                   (... calculate sample ... )
                   (... use cache-item ... ))
          ; REPEATED CODE HERE
          ...]
       ...)))

(nil? cache-item)会在if. 您可以引入一个cache-hit?本地来存储的值,(nil? cache-item)以避免在nil?调用中重复输入;但是,不是出于性能原因,因为实际上应该没有区别。

于 2013-07-26T12:33:00.110 回答