我正在尝试编写一个构建类似于compojure中使用的中间件的宏。
我希望能够致电:
(def-middleware plus-two [x]
(+ 2 x))
结果如下:
(defn plus-two [f]
(fn [x]
(f (+ 2 x)))
我已经远远没有阅读在线指南,但这对我没有用处:
(defmacro def-middleware [fn-name args & body]
'(defn ~fn-name [f]
(fn ~args
(f ~@body))))
任何帮助或指向更好的宏写作指南的指针都会很棒,谢谢。
答案 0 :(得分:8)
让我们看看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))))
不完全是我们追求的!首先要做的事情是:如果你想在宏中取消引用,你需要使用“`”(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=>
答案 1 :(得分:3)
也许这只是一个宏观练习,但定义中间件功能的具体例子并不好 - 你失去了中间件概念给你的很多灵活性。例如,为什么要评估(f (+ 2 x))
而不是(+ 2 (f x))
?两者都是包装此函数的合理方法,并且您的语法无法描述后者。真正只是定义一个函数返回函数是灵活,简单和容易的;这个宏给桌子带来了很少的东西。