2017-12-21 9 views
2

nicht sicher, was hier vor sich geht, aber ich habe diesen Code, wo die Kartenfunktion in meinem repl erfolgreich ausführt, ohne in eine definierte Funktion eingewickelt:Clojure Atom nicht aktualisiert Wenn in Defined Function Wrapped

(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2})) 

(def ages (atom {:above-four '() :below-four '()})) 

(map 
    #(if (> (get-in % [:age]) 4) 
     (swap! ages update-in [:above-four] merge %) 
     (swap! ages update-in [:below-four] merge %)) dogs) 

@ages 
=> {:above-four ({:name "scout", :age 5}), :below-four ({:name "fenley", :age 2} {:name "rux", :age 3})} 

Doch wenn ich die Kartenfunktion als solche definieren:

(def ages (atom {:above-four '() :below-four '()})) 

(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2})) 

(defn test-dogs [] 
    (map 
    #(if (> (get-in % [:age]) 4) 
     (swap! ages update-in [:above-four] merge %) 
     (swap! ages update-in [:below-four] merge %)) dogs) 
     @ages) 

ich folgendes Ergebnis:

=> {:above-four(), :below-four()} 

Ich bin sehr verwirrt, da diese Funktion nur feine gerade von den Clojure docs genommen funktioniert:

(def m1 (atom {:a "A" :b "B"})) 

(defn update-m1 [] 
    (swap! m1 assoc :a "Aaay") 
    @m1) 

=> {:a "Aaay", :b "B"} 
+0

Zeigen Sie genau, wie Sie 'Testhunde' nennen. Ich vermute, das liegt an 'map's Faulheit. Wenn Sie die 'map' in ein' doseq' ändern, wird es repariert? – Carcigenicate

+0

Es gibt auch keinen Grund, 'Atom's hier zu verwenden. Sie werden die Dinge nur etwas komplizieren. – Carcigenicate

+0

Benötigen Sie ein Atom, weil dies ein vereinfachtes Beispiel für ein größeres Programm ist, wo es benötigt wird. Doseq gibt CompilerException zurück java.lang.IllegalArgumentException: doseq benötigt einen Vektor für seine Bindung in spam-problem.core: 2 –

Antwort

5

Da test-dogsmap verwendet, hat es eine faul Sequenz zurückgibt. Die Elemente von Lazy-Sequenzen werden erst realisiert, wenn sie benötigt werden.

Das Problem mit dem Set up wird Sie versuchen, map zu verwenden, um eine Nebenwirkung (das Gespräch zu swap!, eine unreine Handlung) zu laufen, und nie wirklich nutzen das Ergebnis map. Da Sie nie Ergebnisse von map anfordern, wird die Zuordnungsfunktion, die swap! enthält, nie ausgeführt.

Durch die Verwendung von mapv (die eine nicht-faul Vektor zurückgibt) oder doseq (die Nebenwirkungen durchzuführen gemeint ist):

(doseq [dog dogs] 
    (let [k (if (> (:age dog) 4) 
       :above-four 
       :below-four)] 

    (swap! ages update k merge dog))) 

Sie können die Nebenwirkungen zwingen zu laufen.

Ich räumte den Code ein wenig auf. Die von Ihnen verwendeten -in Versionen waren unnötig; wie war der Ruf an get-in. Ich habe auch die redundanten Anrufe zu swap! losgeworden.

Beachten Sie, dass zumindest in Ihrem Beispiel die Verwendung von atom s völlig unnötig ist. Auch wenn Sie einen komplizierteren Anwendungsfall haben, stellen Sie sicher, dass ihre Verwendung gerechtfertigt ist. Veränderbare Variablen sind in Sprachen wie Clojure nicht so gebräuchlich.

Verwandte Themen