macros - tipos - Diferencia impar entre funciones nombradas y anónimas cuando se utiliza la macro de subprocesamiento
que es una macro en excel (2)
Hay algo que me debe perder sobre la macro de subprocesamiento en Clojure.
También tengo un mapa con valores que son mapas, y me gustaría buscar el resultado de otra búsqueda. Deje que el mapa sea un simple {:a {:b 2}}
- primero quiero buscar la clave :a
, que va a dar {:b 2}
, luego buscar b
, el resultado es 2
. La clave para la segunda búsqueda debe ser el resultado de una función.
((fn [x] (get x :b)) ({:a {:b 2} } :a ))
=> 2
Ok, hagámoslo más legible con la macro de subprocesamiento.
(-> {:a {:b 2} } :a (fn [x] (get x :b)))
Es decir :a
como una función en el mapa luego aplique otra función. Bueno, esto no funciona: CompilerException java.lang.IllegalArgumentException: Parameter declaration :a should be a vector
Por extraño que parezca, si la función anónima se extrae a uno nombrado, entonces funciona bien:
(defn f [x] (get x :b))
(-> {:a {:b 2} } :a f)
=> 2
O incluso:
(def f (fn [x] (get x :b)) )
(-> {:a {:b 2} } :a f)
=> 2
¿Por qué hay una diferencia entre cómo funcionan las funciones nombradas y anónimas?
La macro de subprocesamiento ve y altera cada subformulario de la serie antes de que se evalúe esa forma, mediante la inserción recursiva de la forma anterior como primer argumento de cada subformulario.
empiezas con:
(-> {:a {:b 2} } :a (fn [x] (get x :b)))
esto se convierte en:
(-> (:a {:a {:b 2}}) (fn [x] (get x :b)))
esto se convierte en:
(fn (:a {:b {:b 2}}) [x] (get x :b)))
Lo que claramente no es lo que querías en absoluto.
Pero veamos qué sucede si agrega parens extra alrededor de la función anónima:
(-> {:a {:b 2}} :a ((fn [x] (get x :b))))
(-> (:a {:a {:b 2}}) ((fn [x] (get x :b))))
(-> ((fn [x] (get x :b)) (:a {:a {:b 2}})))
((fn [x] (get x :b)) (:a {:a {:b 2}}))
En la última macroexpansión recursiva del formulario ->
ahora nos queda un código válido que hace lo que usted quiere.
Para complementar la respuesta de noisesmith, en este caso particular no necesita la macro threading. La forma idiomática de obtener un valor de un mapa anidado es get-in
. p.ej:
(get-in {:a {:b 2}} [:a :b])
=>
2