1

マクロを作成する関数を定義しようとしていますが、マクロの名前を動的に指定しようとすると問題が発生します。これが私が直面している問題を例示する絞り込まれたコードです:

(defn create-times-macro [n]
  (defmacro thatManyTimes [a]
    `(* ~n ~a)))

(create-times-macro 2)

(thatManyTimes 3) ;; evals to 6

ここまでは順調ですね。ここで、マクロの名前をパラメーターとして指定するとします。

(defn create-times-macro [macroName n]
  (defmacro macroName [a]
    `(* ~n ~a)))

(create-times-macro (symbol "multiplyBy") 3)
(multiplyBy 3) ;; fails with unable to resolve symbol multiplyBy
(create-times-macro "multiplyBy" 3)
(multiplyBy 3) ;; same failure
4

3 に答える 3

4

マクロの使用について混乱しているようです。

  • 関数を作成するマクロ - OK
  • 別のマクロを作成するマクロ - OK
  • マクロを作成する関数 - OK ではありません (一般的でなく、通常ではありません)。

これらすべての点は、関数が実行時のものであるのに対し、マクロはコンパイル時のものであるという事実を示唆しています。通常の方向はコンパイル時から実行時ですが、最後のポイントは実行時からコンパイル時への移行です。

最初のコード例は REPL では機能しますが、コンパイルされた JAR では機能しません。REPLでは、コンパイル時->実行時->印刷->ループにあり、ループのbecozは、実行時からコンパイル->時間に戻るため、REPLで最後のポイントが機能するのはそのためです。コンパイルされたコードでは、コンパイルされたコードだけがあり、evalコンパイル時に戻すことができるコードをコードで使用しない限り、ランタイムの世界しかありません....頭が痛いのを待ってください。

于 2013-02-26T17:43:28.037 に答える
1

この場合、マクロは必要ありません。関数はほとんどの場合に適しており、マクロよりも多くの機能を備えています。たとえば、関数として作成する場合

(defn create-times-fn [n]
  (fn [a]
    (* n a)))

同じ結果が得られます

(def three-times (create-times-fn 3))

(three-times 2)
=> 6

また

(let [three-times (create-times-fn 3)]
  (three-times 2))

そして、それを引数として他の関数に渡すことができます

(map (create-times-fn 2) (range 5))
=> (0 2 4 6 8)

または結果として返すか、他の関数で構成します。マクロを使用すると、これらすべてが失われます。

于 2013-02-26T17:27:00.610 に答える
1

これが最善の方法かどうかはわかりませんが、うまくいきます:

=> (defmacro create-times-macro [macroName n]
     (let [the-name (symbol macroName)]
       `(defmacro ~the-name [a#]
          (* ~n a#))))
#'user/create-times-macro
=> (create-times-macro "hi" 3)
#'user/hi
=> (hi 4)
12
于 2013-02-26T16:35:25.037 に答える