内容简介:Respo 中的 defcomp Macro
;; 宏可以传入参数。 (defmacro inc2 [arg] (list + 2 arg)) (inc2 2) ; -> 4 ;; 不过,如果你尝试配合使用引用列表,会导致错误, ;; 因为参数也会被引用。 ;; 为了避免这个问题,clojure提供了引用宏的另一种方式:` ;; 在`之内,你可以使用~获得外圈作用域的变量。 (defmacro inc2-quoted [arg] `(+ 2 ~arg)) (inc2-quoted 2)
我在 Respo 里遇到一个语法糖的问题, 听说要 Macro 才能解决.
Respo 里定义组件的写法挺长的, 包含了好几层的嵌套函数和缩进:
(def comp-demo (create-comp :demo (fn [content] (fn [cursor] (div {:class-name "demo-container" :style {:color :red}} (comp-text content nil))))))
很多代码是重复的, 我想了下, 简化以后甚至可以这样写:
(defcomp comp-demo [content] (div {:class-name "demo-container" :style {:color :red}} (comp-text content nil)))
原本我不知道有没有办法能做到, 毕竟 Respo 基于高阶函数实现的,
当然, 对于用户来说显然是短的写法更好记了,
除了没有看到 cursor
定义可能会造成困扰之外, 可以说是很好的写法.
后来看到社区其他同学的代码, 发现是可以做到的,
最终得到的代码是这样的:
(defmacro defcomp [comp-name params & body] `(def ~comp-name (create-comp ~(keyword comp-name) (~'fn [~@params] (~'fn [~'cursor] ~@body)))))
要理解这个代码, 需要对 Clojure 里 Macro 的编写有所了解
defmacro
这个语法可以定义 Macro, 后面是名字和参数,
()
表示括号的代码都是符号, 不会被编译器直接执行,
~comp-name
表示其中的 comp-name
是经过计算的, 并不是符号类型或者说代码,
~@body
跟上面类似, 但是加上 @
之后, 表明内容是序列, 可以被展开,
&
放在参数里表示之后多个参数被折叠到 body
变量上, 所以是序列,
为了验证这份代码正常运行, 我用 boot repl
启动一个 Clojure REPL:
boot.user=> (defmacro defcomp [comp-name params & body] #_=> `(def ~comp-name #_=> (create-comp ~(keyword comp-name) #_=> (~'fn [~@params] #_=> (~'fn [~'cursor] ~@body))))) #'boot.user/defcomp
然后尝试展开符号:
boot.user=> (macroexpand-1 '(defcomp comp-demo [content] #_=> (div #_=> {:class-name "demo-container" #_=> :style {:color :red}} #_=> (comp-text content nil)))) (def comp-demo (boot.user/create-comp :comp-demo (fn [content] (fn [cursor] (div {:class-name "demo-container", :style {:color :red}} (comp-text content nil))))))
macroexpand-1
这个函数可以将符号格式的代码进行一次展开,
这里的 '()
跟前面的 ()
是类似的, 表示这里都是代码.
然后我把返回结果格式化一下:
(def comp-demo (boot.user/create-comp :comp-demo (fn [content] (fn [cursor] (div {:class-name "demo-container", :style {:color :red}} (comp-text content nil))))))
基本上是一样的, 不过 create-comp
被带上了命名空间,
当然这个代码运行不了, 因为 create-comp
没定义, 但是至少符号嘛, 还不会报错.
fn
没有被带上命名空间, 是因为用了 ~'fn
写法, 强行转成了符合再转回来.
感兴趣可以扒更多文章看(虽然下面的文章我只看了一部分...)
http://lambdax.io/blog/posts/...
http://www.braveclojure.com/w...
https://aphyr.com/posts/305-c...以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。