Macros 编写宏时获取原始符号名称

Macros 编写宏时获取原始符号名称,macros,clojure,lisp,Macros,Clojure,Lisp,我编写了以下宏,它使用自定义字符串表示形式定义记录 (defmacro defrecord* [rname args] `(defrecord ~rname [~@args] Object (toString [_] ~(let [kvs (->> args (map (fn [arg] [(str arg ": ") arg])) (interpos

我编写了以下宏,它使用自定义字符串表示形式定义记录

(defmacro defrecord*
  [rname args]
  `(defrecord ~rname [~@args]
     Object
     (toString [_]
       ~(let [kvs (->> args
                       (map (fn [arg] [(str arg ": ") arg]))
                       (interpose ", ")
                       (apply concat))]
          `(str ~rname "(" ~@kvs ")")))))
然而,toString返回的并不完全是我所期望的

(defrecord* Foo [bar baz]) 
(.toString (Foo. 3 4))

> "class user.Foo(bar: 3, baz: 4)"
在这种情况下,我希望我的toString返回Foobar:3,baz:4。要获得此格式的字符串表示形式,需要做哪些更改

另外,我应该对上述代码进行哪些更改(如果有的话)以使其更地道?

只需将~rname更改为~name rname:

只需将~rname更改为~name rname:

只需将~rname替换为'~rname-您需要的是实际符号Foo,而不是当前作用域中的值,即类user.Foo

您还必须以错误的顺序应用concat和interpose-您将被视为一个序列,并添加\和\空格字符,而不是单个字符串。交换后,很明显您想要的是mapcat而不是apply concat map。。。。因此,我会用以下内容替换整个let块:

`(str '~rname
      "(" ~@(interpose ", "
                       (mapcat (fn [arg] [(str arg ": ") arg])
                               args))
      ")")
或者,如果您真的想提高性能,可以在编译时而不是运行时计算~str rname

但是请注意,从Clojure 1.3开始,记录已经以与此非常类似的方式打印,因此,如果您只是为了简化调试而这样做,请不要费心。如果您这样做是因为您稍后使用了.toString的输出…那么,无论是谁编写了该代码,都会感到羞耻,因为.toString主要用于调试内容。

只需将~rname替换为'~rname-您想要的是实际的符号Foo,而不是当前作用域中的值,即类user.Foo

您还必须以错误的顺序应用concat和interpose-您将被视为一个序列,并添加\和\空格字符,而不是单个字符串。交换后,很明显您想要的是mapcat而不是apply concat map。。。。因此,我会用以下内容替换整个let块:

`(str '~rname
      "(" ~@(interpose ", "
                       (mapcat (fn [arg] [(str arg ": ") arg])
                               args))
      ")")
或者,如果您真的想提高性能,可以在编译时而不是运行时计算~str rname


但是请注意,从Clojure 1.3开始,记录已经以与此非常类似的方式打印,因此,如果您只是为了简化调试而这样做,请不要费心。如果您这样做是因为以后使用了.toString的输出…那么,无论是谁编写了这些代码,都会感到羞耻,因为.toString主要用于调试东西。

我这样做只是因为我在学习宏。:谢谢我接受这个答案。我这么做只是因为我在学习宏谢谢我接受这个答案,没问题。就惯用语而言,我认为阿马洛伊的回答没有什么可补充的。没问题。就惯用语而言,我认为阿马洛伊的回答没有什么可补充的。