2013-07-26 4 views
0

У меня есть рекурсия с использованием looprecur с довольно сложной логикой. Оказывается, я должен делать то же самое в двух ветвях, что должно привести к рекурсии. Я не верю, что могу абстрагировать это, используя функцию из-за ограничений recur, так как я могу это сделать и не иметь дублирующий код. Должен ли я использовать макрос?Не повторяется в рекурсии

код ниже, и повторил код выделен повторяющийся код ЗДЕСЬ

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

ответ

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))))))))) 
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) дважды в ветке «else» if. Вы можете ввести cache-hit? локально, чтобы сохранить значение (nil? cache-item), чтобы избежать повторного набора номера в вызове nil?; но не по соображениям производительности, так как практически не должно быть разницы.

Смежные вопросы