clojure - lambdas - macro-> con funciones anonimas
lambdas java (3)
(Esto se basa en la answer a la pregunta que publiqué en los comentarios).
la macro ->
toma cada argumento, haciéndolo una lista si es necesario (aplicando funciones "brutas" a ningún argumento - convirtiendo myfunc
a (myfunc)
), y luego inserta el primer argumento en ->
como segundo argumento en cada una de esas listas.
así que (-> foo myfunc)
convierte en (-> foo (myfunc))
convierte en (myfunc foo)
, aproximadamente.
todo esto se describe en los documentos para ->
.
El problema con las funciones anónimas es que son generadas por una macro lectora como se describe aquí (desplácese hacia abajo) . eso significa que #(...)
se convierte ( antes de la expansión de macro normal) a (fn [...] ...)
. que está bien, pero, críticamente, ya es una lista .
por lo que la macro cree que la función anónima ya se está aplicando, cuando en realidad está encontrando una definición de función (ambas son listas). y agregar los parens "extra", como se describe anteriormente en la otra respuesta, aplica la función anónima a ningún argumento.
la razón de este comportamiento no intuitivo es que la heurística dwim (do-what-i-mean, not dwim-witted, aunque ...) utilizada por la macro ->
, agregó para permitirle proporcionar funciones "simples" en lugar de Luego de requerir que los aplique a ningún argumento al incluirlos en una lista, es solo una heurística (simplemente prueba una lista) y se confunde con la definición de función creada por la macro del lector.
[en mi opinión de mal humor, ->
está mal implementado y debería rechazar todas las funciones "simples", en su lugar solo acepta aplicaciones de funciones; Entonces parecería más consistente. si no, al menos los documentos podrían ser más claros, explicando la semántica motivadora detrás de colocar las cosas en las listas.]
Entiendo que la macro -> in clojure está aplicando todas las funciones proporcionadas al argumento dado. Sin embargo, no parece funcionar con funciones anónimas (en clojure 1.3.0). Por ejemplo:
user> (-> 4 inc inc dec)
5
Pero:
user> (-> 4 #(+ % 1) #(- % 1) #(+ % 1))
Devuelve el error:
clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector
[Thrown class java.lang.ClassCastException]
Si alguien sabe de alguna manera sería útil. ¡Gracias!
Puedes tener funciones anónimas en macros de Clojure. Tienes problemas porque te faltan algunos paréntesis. :) Su ejemplo se edita a continuación.
(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
Su caso específico podría haber sido resuelto simplemente usando:
(-> 4 (+ 1) (- 1) (+ 1))
donde la primera macro del hilo ->
se encarga de insertar el resultado del paso anterior como primer argumento en la función "actual".
La confusión surge del hecho de que ->
no es una función sino una macro y los argumentos se tratan de manera muy diferente en este caso como se explica en otras respuestas.