2

私は記録を持っています(defrecord Rec [id])

私はそれを次のように扱います

(def my ( Rec. 2 ))
(println (:id my))

ここで、レコード定義をマクロに置き換えたいと思います。ただ書くことができるように

(r 2) 
(println (:id my))

マクロを書いた

(defmacro r [id]
   (list 'def 'my (symbol "(") 'Rec. id (symbol ")")))

macroexpandで確認しました

(macroexpand-1 '(r 2))  => (def my ( Rec. 2 ))

しかし、私は乗りRuntimeException: Too many arguments to defます(r 2)

4

1 に答える 1

10

左のパレンからシンボルを作成することは、左のパレンでテキストを評価することと同じではありません。前者には特別な意味はありません。後者の場合、リーダーはネストされたリストを生成し、それが評価されます。

言い換えると、Clojureは、テキスト(または記号のリスト)ではなく、データ構造を評価します。REPLに何かを入力すると、そのテキストがデータ構造に読み込まれ、データ構造が評価されます。

これが正しく機能するためには、マクロがネストされたリスト自体を生成する必要があります。

(defmacro r [id]
  (list 'def 'my (list 'Rec. id)))

または、さらに良いことに、構文引用演算子を使用します。

(defmacro r [id]
  `(def my (Rec. ~id)))

説明のために、Clojureコードをテキストとして読み取ったときに何が起こるかを確認できます。

(read-string "(def my (Rec. 2))")
=> (def my (Rec. 2))
(map type (read-string "(def my (Rec. 2))"))
=> (clojure.lang.Symbol clojure.lang.Symbol clojure.lang.PersistentList)
于 2012-08-01T20:19:55.427 に答える