2012-08-30 6 views
7

He estado buscando en la fuente para defmacro que utiliza "dejo" en su definición:En clojure, ¿cómo se puede definir defmacro en términos de sí mismo?

(def 

^{:doc "Like defn, but the resulting function name is declared as a 
    macro and will be used as a macro by the compiler when it is 
    called." 
    :arglists '([name doc-string? attr-map? [params*] body] 
       [name doc-string? attr-map? ([params*] body)+ attr-map?]) 
    :added "1.0"} 
defmacro (fn [&form &env 
       name & args] 
      (let [prefix (loop [p (list name) args args] 

Sin embargo, "vamos" se define como una macro en sí:

(defmacro let 
    "binding => binding-form init-expr 

    Evaluates the exprs in a lexical context in which the symbols in 
    the binding-forms are bound to their respective init-exprs or parts 
    therein." 
    {:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]} 
    [bindings & body] 
    (assert-args 
    (vector? bindings) "a vector for its binding" 
    (even? (count bindings)) "an even number of forms in binding vector") 
    `(let* ~(destructure bindings) [email protected])) 

Puede alguien explicar cómo esto funciona, ya que no puedo entender cómo se puede definir "defmacro" en términos de cosas que necesitan que se defina "defmacro". (si eso tiene sentido :)

Respuesta

5

Las macros recursivas funcionan bien y existen en muchos lugares tanto en el núcleo del lenguaje clojure como en otros programas. Las macros son solo funciones que devuelven S-Expressions, por lo que pueden ser recursivas al igual que las funciones. En el caso de let en su ejemplo, realmente llama a let* que es una función diferente (está bien tener * en un nombre de funciones), así que aunque las macros recursivas están bien, no es un ejemplo de ellas

+2

¿No se trata de la aparente definición circular? – Jeremy

8

Esto es posible porque antes de definir la función defmacro en core.clj ya existe una definición de let en this location (que se redefine más adelante). Las macros son solo funciones normales y las var están asociadas con la clave de metadatos :macro con el valor true para que en tiempo de compilación el compilador pueda diferenciar entre una macro (que se ejecuta en tiempo de compilación) con una función, sin esta meta clave no hay forma de diferenciar entre una macro y una función porque la macro misma es una función que pasa a procesar S-expressions.

+0

El que usted señaló también se basa en sí mismo siendo definido – Zubair

+2

Nope: '(fn * let [& form & env & decl] (cons 'let * decl))' .. ¿dónde depende de let? Está definiendo la función let. Utiliza let *, que ya está definido en el código java de clojure – Ankur

Cuestiones relacionadas