2016-08-07 69 views
0

Bei Verwendung von reduce gibt es die reductions Funktion, um die Liste der aufeinanderfolgenden Reduzierungen anzuzeigen. Gibt es etwas Ähnliches Debug loop in Clojure?clojure loop siehe Werte

+0

Hat es eine faule Sequenz zurückkehren wie 'reductions' tut? –

Antwort

2

@progo ist richtig, Sie können immer einen weiteren Akkumulator hinzufügen, aber wenn Sie es nicht wirklich jedes Mal tun möchten, könnten Sie einige Makros machen, die für Sie semantisch dem Standard loop/recur entsprechen (ich denke an zwei loop+/recur+ (letztere implizit verwendet werden würde):

(defmacro recur+ [& args] 
    (let [names (repeatedly (count args) gensym)] 
    `(let ~(vec (interleave names args)) 
     (recur [email protected] (conj ~'&loop-history [[email protected]]))))) 

(defmacro loop+ [bindings & body] 
    (let [val-names (repeatedly (/ (count bindings) 2) gensym) 
     vals (take-nth 2 (rest bindings)) 
     binding-lefts (take-nth 2 bindings)] 
    `(let [[email protected](interleave val-names vals)] 
     (loop [[email protected](interleave binding-lefts val-names) 
       ~'&loop-history [~(vec val-names)]] 
     [email protected](clojure.walk/postwalk-replace 
      {'recur 'recur+ 
      'loop 'loop+} 
      body))))) 

wie Sie sehen können, loop+ führt den impliziten Wert &loop-history und ersetzt alle inneren loop s und recur s mit loop+ und recur+, während recur+ fügt diese implizite var derhinzuAnruf (der Teil mit val-names, vals und binging-lefts ist wesentlich, um die doppelte Bewertung der Formulare zu vermeiden, die an die loop+ übergeben werden).

so, stellen Sie sich eine Schleife wie dieses:

user> (loop [a 1 b 2] 
     (if (<= b 10) 
      (recur a (inc b)) 
      (str a " " b))) 
"1 11" 

die neue Schleife verwenden nur Schleife aufrufen + statt Schleife:

user> (loop+ [a 1 b 2] 
     (if (<= b 10) 
      (recur a (inc b)) 
      (str a " " b))) 
"1 11" 

es in den folgenden erweitert wird:

(let* 
    [G__20054 1 G__20055 2] 
    (loop* 
    [a G__20054 b G__20055 &loop-history [[G__20054 G__20055]]] 
    (if (<= b 10) 
     (let* 
     [G__20056 a G__20057 (inc b)] 
     (recur 
      G__20056 
      G__20057 
      (conj &loop-history [G__20056 G__20057]))) 
     (str a " " b)))) 

jetzt &loop-history ist überall zugänglich innerhalb der Schleife +:

user> (loop+ [a 1 b 2] 
     (if (<= b 10) 
      (do 
      (println "history length: " (count &loop-history) 
        "last item: " (last &loop-history)) 
      (recur a (inc b))) 
      {:result (str a " " b) 
      :history &loop-history})) 

;; history length: 1 last item: [1 2] 
;; history length: 2 last item: [1 3] 
;; history length: 3 last item: [1 4] 
;; history length: 4 last item: [1 5] 
;; history length: 5 last item: [1 6] 
;; history length: 6 last item: [1 7] 
;; history length: 7 last item: [1 8] 
;; history length: 8 last item: [1 9] 
;; history length: 9 last item: [1 10] 
;; {:result "1 11", :history [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10] [1 11]]} 

Ankündigung, dass es führt auch &loop-history für innere Schleifen, ohne die Notwendigkeit, den Quellcode zu ändern:

user> (loop+ [a 1 b 2] 
     (if (<= b 10) 
      (do (println :outer-hist &loop-history) 
       (recur a (inc b))) 
      (loop [a a] 
      (if (>= a -4) 
       (do (println :inner-hist &loop-history) 
        (recur (dec a))) 
       (str a b))))) 

:outer-hist [[1 2]] 
:outer-hist [[1 2] [1 3]] 
:outer-hist [[1 2] [1 3] [1 4]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9]] 
:outer-hist [[1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [1 10]] 
:inner-hist [[1]] 
:inner-hist [[1] [0]] 
:inner-hist [[1] [0] [-1]] 
:inner-hist [[1] [0] [-1] [-2]] 
:inner-hist [[1] [0] [-1] [-2] [-3]] 
:inner-hist [[1] [0] [-1] [-2] [-3] [-4]] 
"-511" 
2

loop/recur ist zwingend erforderlich als reductions; Sie können sehr gut nur Ihre eigene Protokollierung in den Schleifenkörper selbst einfügen oder eine Atomliste von Werten beibehalten oder, am funktionalsten, einen (anderen) Akkumulator in die Schleifenargumente einführen.