Clojure China

尝试理解定义 macro 的 macro...

#1

@isaac 提交到 Respo 的代码 https://github.com/Respo/respo/blob/f7e162a105626ab49291728545672784f881566b/polyfill/respo/macros.cljc#L21-L34

用来批量定义的标签的 Macro, 然后是用 Macro 实现的,

(def support-elements '[a body br button canvas code div footer
                        h1 h2 head header html hr img input li link
                        option p pre script section select span style textarea title
                        ul])

(defn gen-dom-macro [el]
  `(defmacro ~el [~'props ~'& ~'children]
     `(create-element ~(keyword '~el) ~~'props ~@~'children)))

(defmacro define-element-macro []
  (println "called during compile time")
  `(do ~@(clojure.core/map gen-dom-macro support-elements)))

(define-element-macro)

最核心的一段代码, 这段代码里在 Macro 内部定义了 Macro:

(defn gen-dom-macro [el]
  `(defmacro ~el [~'props ~'& ~'children]
     `(create-element ~(keyword '~el) ~~'props ~@~'children)))

~el 这个写法我知道, 在 `() 内部用来 unquote 的, 在编译过程插入 el 的数据, 应该是 literal 和 symbol.
~@ 语法我也知道, 插入 list 数据的同时展开成多项嘛… 应该还是 symbol. sequence 也行吧.
~'props 我也知道, 这里的 props 生成的是调用 macro 位置环境当中的 props, 可以是表达式了,

但是 ~(keyword '~el)~~'props 还有 ~@~'children 就不懂了 - -
这个求值顺序是怎么回事?
如果从运行的结果反推, 比如 ~~'props 后面的 ~'props 可以是对应到参数里那个的,
类似地, ~(keyword '~el)~@~'children 后面的部分也可以在第二行找到对应.
但是 Clojure 自身怎么确定这个求值的顺序? 不明觉厉…

1赞
#2

:stuck_out_tongue_closed_eyes:, 成为 Respo 的贡献者

2赞
#3

关于嵌套 syntax-quote 与 ~ 的匹配问题,lisp 里面有一个原则:

A tilde(~) matches a syntax-quote if there are the same number of tildes as syntax-quotes between them

表现就是最外层的 syntax-quote 与最内层的 ~ 匹配。

所以~(keyword '~el) 会先匹配最外层的 syntax-quote (defmacro前面那个),返回~(clojure.core/keyword 'h1),假设el传入了h1,其他同理。

参考:

1赞