2010-02-22 15 views
28

Tengo una secuencia (foundApps) devuelta desde una función y quiero asignar una función a todos sus elementos. Por alguna razón, apply y count trabajo para el sequnece pero map no:Clojure aplicar frente al mapa

(apply println foundApps) 
(map println rest foundApps) 
(map (fn [app] (println app)) foundApps) 
(println (str "Found " (count foundApps) " apps to delete")))) 

Lienzo:

{:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(2)>} {:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(4)>} 
Found 2 apps to delete for id 1235 

Así apply parece funcionar felizmente para la secuencia, pero map no. ¿Dónde estoy siendo estúpido?

Respuesta

31

Lo más probable es que esté siendo golpeado por la pereza de map. (map produce una secuencia perezosa que solo se realiza cuando algún código usa realmente sus elementos. Y aun así la realización ocurre en fragmentos, por lo que debe recorrer toda la secuencia para asegurarse de que todo se haya realizado). Intente ajustar la expresión map en un dorun:

(dorun (map println foundApps)) 

Además, dado que lo estás haciendo sólo por los efectos secundarios, podría ser más limpio para usar en lugar doseq:

(doseq [fa foundApps] 
    (println fa)) 

Tenga en cuenta que (map println foundApps) debería funcionar bien en el REPL; Supongo que lo has extraído de algún lugar de tu código donde no está siendo forzado. No hay ninguna diferencia con doseq que sea estricta (es decir, no floja) y recorra sus secuencias de argumentos bajo cualquier circunstancia. También tenga en cuenta que doseq devuelve nil como su valor; solo es bueno para los efectos secundarios. Finalmente me salté el rest de su código; es posible que haya querido decir (rest foundApps) (a menos que sea un error tipográfico).

También tenga en cuenta que (apply println foundApps) imprimirá todas las foundApps en una línea, mientras que (dorun (map println foundApps)) imprimirá cada miembro de foundApps en su propia línea.

+3

¿hay alguna diferencia entre 'dorun' y' doall'? –

8

Una pequeña explicación podría ayudar. En general, utiliza apply para proyectar una secuencia de elementos en un conjunto de argumentos para una función. Entonces, aplicar una función a algunos argumentos solo significa pasarlos como argumentos a la función, en una sola llamada a función.

La función de mapa hará lo que usted desee, cree un nuevo seq conectando cada elemento de la entrada a una función y luego almacenando la salida. Sin embargo, lo hace de forma perezosa, por lo que los valores solo se computarán cuando realmente itere sobre la lista. Para forzar esto, puede usar la función (doall my-seq), pero la mayoría de las veces no tendrá que hacer eso.

Si necesita realizar una operación inmediatamente porque tiene efectos secundarios, como imprimir o guardar en una base de datos o algo así, entonces normalmente usa doseq.

Así que para añadir "foo" a todas sus aplicaciones (suponiendo que son cadenas):

(mapa (fn [aplicación] (aplicación str "foo"))-aplicaciones encontradas)

o utilizando el shorhand para una función anónima:

(mapa # (str% "foo") que se encuentran-aplicaciones)

Hacer lo mismo pero a imprimir de inmediato se puede hacer con cualquiera de los siguientes:

(Doall (mapa # (println%)-aplicaciones encontradas))

(doseq [App Encontrados-aplicaciones] (println aplicación))

13

Tengo una explicación simple de la que falta esta publicación. Imaginemos una función abstracta F y un vector. Así,

(apply F [1 2 3 4 5]) 

se traduce en

(F 1 2 3 4 5) 

lo que significa que F tiene que ser, en el mejor caso variadic.

Mientras

(map F [1 2 3 4 5]) 

traduce en

[(F 1) (F 2) (F 3) (F 4) (F 5)] 

que significa que F tiene que ser de una sola variable o al menos se comportan de esta manera.

Existen algunos matices acerca de los tipos, ya que map realmente devuelve una secuencia perezosa en lugar de vector. Pero, en aras de la simplicidad, espero que sea perdonable.

+0

¡Gracias por la respuesta conceptual simple! – JaKXz

+3

Gran explicación de aplicar frente al mapa. Hay un nombre para lo que aplica en otros lenguajes de programación dinámica, se llama splatting o desempaquetar. – blushrt

+0

Mi vida es más simple ahora. Gracias (: – stryku