why guide code macros clojure nested

macros - guide - clojure syntax



Macro anidada de Clojure (1)

Creo que lo que estás buscando es una forma de declarar macros locales dentro de las funciones. El paquete clojure.tools.macro tiene una forma de macrolet , que creo que debería poder modificar para crear una macro para las búsquedas de matriz local.

Aquí hay un pequeño ejemplo que armé:

; project.clj (defproject testproject "1.0.0-SNAPSHOT" :description "FIXME: write description" :dependencies [[org.clojure/clojure "1.5.0"] [org.clojure/tools.macro "0.1.2"]]) ; src/testproject/core.clj (ns testproject.core (:require [clojure.tools.macro :refer [macrolet]])) (defn my-test [] (let [n 1000 arr (int-array n (range 10))] (macrolet [(lookup [i] (list `aget ''arr i))] (loop [i 0, acc 0] (if (< i n) (recur (inc i) (+ acc (lookup i))) acc)))))

En el ejemplo, utilizo macrolet para declarar una macro llamada lookup que hará que (lookup 5) expanda (lookup arr 5) , que es lo que creo que está buscando.

Observe cómo debe tener cuidado al hacer referencia a arr desde dentro de la definición de macro local. Si acaba de declarar la macro como `(aget arr ~i) , entonces trata de encontrar un símbolo de arr calificado, que no existe. Alternativamente, podría declarar la macro como `(aget ~''arr ~i) , pero sentí que (list `aget ''arr i) veía mucho mejor.

Ahora puede dar un paso más y usar defmacro para crear una macro que incluya macrolet dentro, que puede usar para simplificar la declaración de matrices con una macro de búsqueda local. Dejamos esto como un ejercicio para el lector.

Dado que las macros son tan sutiles, y las macros de anidamiento en las macros solo empeoran las cosas, decidí que probablemente sería más útil dar un ejemplo y dejarte ver cómo funciona:

(defmacro lookup-binding [[fn-sym value] & body] (let [array-sym (symbol (str fn-sym "-raw"))] `(let [~array-sym ~value] (macrolet [(~fn-sym [i#] (list aget ''~array-sym i#))] ~@body)))) (defn my-test2 [] (let [n 1000] (lookup-binding [arr (int-array n (range 10))] (loop [i 0, acc 0] (if (< i n) (recur (inc i) (+ acc (arr i))) acc)))))

Descargo de responsabilidad: solo estoy tratando de demostrar que esto es posible , no que sea una buena idea. Personalmente, no creo que valga la pena evitar toda esta complejidad adicional. Sugeriría usar solo aget ya que son solo unos pocos caracteres adicionales, y hará que tu código sea más claro / legible.

¿Es posible macro macro devuelto? Me gustaría simplificar el código máximo, y puedo hacerlo usando una macro que devuelve la función. Sin embargo, es demasiado alto y es demasiado lento. Para mantener el código más legible, no usé sugerencias de tipo, pero incluso con ellas, mi código es ~ 5 veces más lento.

Mi inglés no es muy preciso, así que escribo lo que tengo y lo que quería tener.

Tengo esto...

(defmacro series [java-array] `(fn ([i#] (aget ~java-array i#)) ([start# stop#] (let [limit# (unchecked-subtract-int stop# start#) result# (double-array limit#)] (loop [i# 0] (if (< i# limit#) (let [r# (double (aget ~java-array i#))] (aset result# i# r#) (recur (inc i#))) result#))))))

Quiero algo como esto...

(defmacro series [java-array] `(defmacro blabla ([i#] `(aget ~~java-array i#)) ([start# stop#] `(let [limit# (unchecked-subtract-int stop# start#) result# (double-array limit#)] (loop [i# 0] (if (< i# limit#) (let [r# (double (aget ~~java-array i#))] (aset result# i# r#) (recur (inc i#))) result#))))))

Pero cuando llamo esto ...

Wrong number of args (1) passed to: blabla

Un ejemplo más simple.

Tengo muchas matrices de Java. No quiero usar aget. Quiero que la macro se expanda a (aget array-name i) . Escribo una macro que se expande a (fn [n] (aget array-name i)) , pero esto es una sobrecarga innecesaria.

(defmacro series [arr] `(fn [i#] (aget (longs ~arr) (int i#))))

Ahora declaro la serie, como "fecha", y la llamo de esta manera (date i) , que me devolverá el elemento "i" de la matriz.