2012-08-30 12 views
7

私はその定義に「聞かせて」使用するのdefmacroのソースを見てきた:どのようにしてdefmacroを自分自身で定義できますか?

(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] 

しかし、マクロ自体として定義される「せ」:

(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])) 

誰かがどのように説明することができます既に定義されている "defmacro"を必要とするものに関して "defmacro"をどのように定義することができるのか理解できないので、これは機能します。 (それが意味をなさない場合:)

答えて

5

recusriveマクロはうまく動作し、クロージャー言語のコアと他のプログラムの両方で多くの場所で発生します。 マクロはS-Expressionsを返す関数なので、関数と同様に再帰的に使用できます。あなたの例ではletの場合、それは実際には別の関数(関数名に*があるべきです)であるlet*を呼び出すので、再帰的なマクロは問題ありませんが、これはその例ではありません

+2

明らかに円形の定義についての質問ではありませんか? – Jeremy

8

defmacroをcore.cljに定義する前に、this locationletという定義があります(後で再定義されるため)。マクロは単なる通常の関数であり、束縛されているvarはメタデータキー:macroの値がtrueであるため、コンパイル時にコンパイラはこのメタキーなしで(コンパイル時に実行される)マクロを区別することができますマクロ自体はS式を処理する関数なので、マクロと関数を区別することができます。

+0

あなたが指し示したのは、それ自体が定義されていることに依存しています – Zubair

+2

いいえ: '(fn * let [&form&env&decl](cons 'let * decl))' ..それはletに依存していますか? let関数を定義しています。これは、clojureのjavaコードで既に定義されているlet *を使用します – Ankur

関連する問題