我正在尝试编写一个构建类似于compojure中使用的中间件的宏.
我希望能够打电话:
(def-middleware plus-two [x]
(+ 2 x))
Run Code Online (Sandbox Code Playgroud)
结果如下:
(defn plus-two [f]
(fn [x]
(f (+ 2 x)))
Run Code Online (Sandbox Code Playgroud)
我已经远远没有阅读在线指南了,但它对我不起作用:
(defmacro def-middleware [fn-name args & body]
'(defn ~fn-name [f]
(fn ~args
(f ~@body))))
Run Code Online (Sandbox Code Playgroud)
任何帮助或指向更好的宏写作指南的指针都会很棒,谢谢.
让我们看看是什么macroexpand-1给了我们:
user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x))))
(defn
~fn-name
[f]
$
(fn ~args$ (f (clojure.core/unquote-splicing body))))
Run Code Online (Sandbox Code Playgroud)
不完全是我们追求的!首先要做的事情是:如果你想在宏中取消引用,你需要使用"`"(quasiquote/syntax-quote运算符),而不是"'".另外,我不确定你用这些美元符号后会怎样,但可能是因为你正在寻找gensym用于卫生的clojure方便的捷径.但是你在使用它的每个标识符之后立即需要它(所以[f#],不是[f]$),并且在每次出现标识符时都需要它.而你不与需要它args.将所有这些放在一起:
user=> (defmacro def-middleware [fn-name args & body] `(defn ~fn-name [f#] (fn ~args (f# ~@body))))
#'user/def-middleware
user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x))))
(clojure.core/defn
plus-two
[f__594__auto__]
(clojure.core/fn [x] (f__594__auto__ (+ 2 x))))
nil
user=>
Run Code Online (Sandbox Code Playgroud)