2010-08-22 3 views
12

Ok Hier ist, was ichclojure latente Funktionsausführung

(defn addresses [person-id] 
;addresses-retrival) 

(defn person [id] 
    (merge {:addresses (addresses id)} {:name "john"})) 

In der obigen Person Funktion zu tun versuche ich Adressen will nur bei Bedarf abgerufen werden, wie es nur, wenn ich tue

(:addresses (person 10)) 

und nicht, wenn

Ich bin mir nicht sicher, ob ich über dieses Recht gehe, neu zu sein clojure.

Antwort

10

Sie können Verzögerung verwenden.

(Person 2) wird dann eine verzögerte zurückgeben, ohne etwas zu bewerten. Um auf den Inhalt zuzugreifen und das verzögerte Objekt auszuwerten, verwenden Sie force oder deref (oder @).

(:addresses @(person 5)) 

Alternativ können Sie die Verzögerung nur auf die Adresse setzen.

(defn person [id] 
    {:addresses (delay (addresses id)) :name "john"}) 

das kann je nach Ihrem Problem netter sein.

Es erlaubt zu definieren:

(defn get-address [person] 
    @(:address person)) 

, die die verzögerte Adresse bekommen und es zwingen. (Erzwingen bedeutet, dass das erste Mal berechnet wird und das erzwungene Ergebnis zu anderen Zeiten abgerufen wird).

+0

Vielen Dank. Ich fragte mich, ob dies transparent gemacht werden könnte, so dass es zum ersten Mal ausgewertet werden könnte, wenn es verwendet wird. Anstatt die Auswertung manuell zu erzwingen? – Surya

+0

Ich glaube nicht. Clojure ist eindeutig in Faulheit und Kraft, soweit ich weiß. –

+0

Meine Lazymap [Bibliothek] (http://bitbucket.org/kotarak/lazymap) macht genau das. Es bietet transparente Drop-Ins für alle Kartentypen, die ihre Werte nur dann berechnen, wenn sie wirklich abgerufen werden. – kotarak

1

Zumindest was Sequenzen angeht, ist Clojure verdammt faul, ohne dass es erzählt werden muss.

Hier Ihre Adresse Abruf als das Zählen der Modellierung versuchen:

(defn addresses [person-id] 
    (iterate #(do (println %) (inc %)) person-id)) 

(defn person [id] 
    (merge {:addresses (addresses id)} {:name "john"})) 

(def people (map person (range 100))) 

Bisher wird es nichts gedruckt haben, aber wenn Sie sagen:

(doall (take 5 (:addresses (nth people 10)))) 

Dann sollten Sie sehen die Druck geschieht in genau den Fällen, die passieren müssen, um fünf auf dem zehnten Platz zu zählen. Ich könnte mir vorstellen, dass das die Art von Verhalten ist, das du willst?

erhalten also Ihre Adresse Lookup einen faulen Sequenz zu erzeugen (Karte, Filter, reduzieren werden alle tun)

0

ich etwas in der Nähe vorschlagen können, was Sie erwarten.

; Note the use of anonymouns function. #(addresses id) 
(defn person [id] 
    (merge {:addresses #(addresses id)} {:name "john"})) 

; :addresses returns a function. Evaluate it by wrapping it in another set of parans. 
((:addresses (person 10))) 
1

Sie können eine Funktion aus der addresses Funktion zurück, die, wenn später die Adressen abrufen genannt. Etwas wie folgt aus:

(defn addresses [person-id] 
#(;addresses-retrival)) 

(defn person [id] 
    (merge {:addresses ((addresses id))} {:name "john"})) 

Hinweis als die addresses Funktion gibt eine anonyme Funktion (erstellt mit #) und die person Funktion aufruft, dass anonyme Funktion ein zusätzliches Paar Pars verwenden.

0

Denken Sie daran, dass Verzögerungen memoisiert sind, so dass aufeinanderfolgende Aufrufe Ihrer Adressenverzögerung immer die gleiche Adresse wie bei der ersten Verspätung der Verzögerung liefern.

(defn addresses [person-id] 
    {:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."}) 

(defn person [id] 
    (merge {:addresses (delay (addresses id))} {:name "john"})) 

(let [person1 (person 1)] 
    (println @(:addresses person1)) 
    (println @(:addresses person1))) 

wird dieser Druck:

{:home 65 Cool St., :work 1243 Boring St.} 
{:home 65 Cool St., :work 1243 Boring St.} 

Beachten Sie, wie die Heimadresse auf dem zweiten deref der Verzögerung unverändert ist.

Wenn Sie dieses Verhalten nicht möchten, müssen Sie stattdessen eine Funktion schließen.

(defn addresses [person-id] 
    {:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."}) 

(defn person [id] 
    (merge {:addresses (fn [] (addresses id))} {:name "john"})) 

(let [person1 (person 1)] 
    (println ((:addresses person1))) 
    (println ((:addresses person1)))) 

wird dieser Druck:

{:home 16 Cool St., :work 1243 Boring St.} 
{:home 31 Cool St., :work 1243 Boring St.} 

Beachten Sie, wie die Heimat-Adresse auf dem Unter sequent Aufruf zur Schließung anders war.

Also, wenn Sie addresses Funktion Nebeneffekt ist, sagt Adressen aus einer Datenbank holt. Und die Personen können ihre Adressen ändern, und Sie möchten, dass Ihr Code immer die aktuellste Adresse hat. Das ist etwas, das Sie im Auge behalten sollten, wenn Delay für Sie arbeitet oder wenn eine Funktionsschließung ein besserer Kandidat wäre.