guide code lisp clojure macros defn

lisp - code - clojure guide



Ayúdame a escribir una macro de Clojure que agregue automáticamente metadatos a una definición de función (1)

Me doy cuenta de que la primera regla de Macro Club es No usar macros, por lo que la siguiente pregunta es más un ejercicio de aprendizaje de Clojure que cualquier otra cosa (me doy cuenta de que este no es necesariamente el mejor uso de las macros).

Quiero escribir una macro simple que actúa como una envoltura alrededor de una macro regular (defn) y termina agregando algunos metadatos a la función definida. Así que me gustaría tener algo como esto:

(defn-plus f [x] (inc x))

... expandir a algo como esto:

(defn #^{:special-metadata :fixed-value} f [x] (inc x))

En principio, esto no me parece tan difícil, pero estoy teniendo problemas para identificar las características específicas de obtener [args] y otras formas en la función definida para que se analicen correctamente.

Como beneficio adicional, si es posible, me gustaría que la macro sea capaz de manejar todas las formas dispares de definición (es decir, con o sin cadenas de documentación, definiciones de aridades múltiples, etc.). Vi algunas cosas en el clojure-contrib/def que parecían posiblemente útiles, pero fue difícil encontrar un código de muestra que las usara.


Actualizado:

La versión anterior de mi respuesta no fue muy robusta. Esto parece ser una forma más simple y apropiada de hacerlo, robada de clojure.contrib.def :

(defmacro defn-plus [name & syms] `(defn ~(vary-meta name assoc :some-key :some-value) ~@syms)) user> (defn-plus ^Integer f "Docstring goes here" [x] (inc x)) #''user/f user> (meta #''f) {:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line 1, :arglists ([x]), :doc "Docstring goes here", :some-key :some-value, :tag java.lang.Integer}

#^{} y with-meta no son lo mismo. Para obtener una explicación de la diferencia entre ellos, consulte la discusión de Rich en la lista de correo de Clojure . Todo es un poco confuso y ha aparecido muchas veces en la lista de correo; Véase también here por ejemplo.

Tenga en cuenta que def es una forma especial y maneja los metadatos de forma un poco extraña en comparación con otras partes del lenguaje. Establece los metadatos de la variable que estás definiendo a los metadatos del símbolo que nombra la variable; Esa es la única razón por la que funciona lo anterior, creo. Vea la clase DefExpr en Compiler.java en la fuente de Clojure si desea ver las agallas de todo.

Finalmente, la página 216 de Programación Clojure dice:

Generalmente, debe evitar las macros del lector en las expansiones de macro, ya que las macros del lector se evalúan en el momento de la lectura, antes de que comience la expansión de la macro.