2010-08-22 11 views
12

Ok aquí es lo que estoy tratando de hacerclojure ejecución de la función diferida

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

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

En la función de la persona por encima de lo que quiero direcciones para que sea recuperado sólo en la demanda, al igual que sólo cuando hago

(:addresses (person 10)) 

y no cuando

(person 10) 

No estoy seguro de si voy por este derecho, ser nuevo en clojure.

Respuesta

10

Puede usar la demora.

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

(persona 2) se devolverá un retraso, sin evaluar nada. Para acceder al contenido y evaluar el objeto retrasado, use force o deref (o @).

(:addresses @(person 5)) 

Como alternativa, puede poner el retraso solo en la dirección.

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

que puede ser más agradable dependiendo de su problema.

Permite definir:

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

que obtendrá la dirección retrasado y forzarlo. (Forzar significa calcular la primera vez y recuperar el resultado forzado en cualquier otro momento).

+0

muchas gracias. Me preguntaba si esto podría hacerse transparente para que pueda ser evaluado la primera vez que se usa. En lugar de forzar manualmente la evaluación? – Surya

+0

No lo creo. Clojure es explícito en la pereza y la fuerza, hasta donde yo sé. –

+0

My lazymap [library] (http://bitbucket.org/kotarak/lazymap) hace exactamente eso. Proporciona drop-ins transparentes para todos los tipos de mapas, que calculan sus valores solo en caso de que realmente se recuperen. – kotarak

1

Al menos en lo que se refiere a las secuencias, clojure es bastante flojo sin que sea necesario contarlo.

Aquí, modelando su dirección de recuperación como contar, probar:

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

Hasta el momento no se han imprimido nada, pero si usted dice:

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

Entonces usted debe ver el la impresión ocurre exactamente en los casos que deben pasar para contar hasta cinco en el décimo lugar. Me imagino que ese podría ser el tipo de comportamiento que quieres?

así que realiza su búsqueda de direcciones para producir una secuencia perezosa (mapa, filtro, se reducirá todos lo hacen)

0

puedo sugerir algo parecido a lo que espera.

; 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

Puede devolver una función a partir de la función addresses que cuando se llamó más tarde va a recuperar las direcciones. Algo como esto:

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

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

Nota de la función addresses devuelve una función anónima (creada usando #) y la función person llama a esa función anónima usando un par extra de parens.

0

Recuerde que los retrasos se memorizan, por lo que las llamadas sucesivas de su dirección demorarán siempre la misma dirección que la primera vez que eliminó el Retraso.

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

Esto imprimirá:

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

Aviso cómo el domicilio no se ha modificado en el segundo DEREF de la demora.

Si no desea este comportamiento, debe usar un cierre de función.

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

Esto imprimirá:

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

Note como la dirección de su casa era diferente en la llamada sub-secuente al cierre.

Por lo tanto, si su función es addresses tiene un efecto secundario, por ejemplo, recupera las direcciones de una base de datos. Y las personas pueden cambiar sus direcciones, y usted querría que su código siempre tenga la dirección más reciente, es algo a tener en cuenta si Delay funciona para usted o si el cierre de una función sería un mejor candidato.

Cuestiones relacionadas