5

我正在尝试编写一个宏来构建类似于 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))))

任何帮助或指向更好的宏编写指南的指针都会很棒,谢谢。

4

2 回答 2

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))))

不正是我们所追求的!首先要做的事情:如果你想在宏中取消引用,你需要使用“`”(准引号/语法引号运算符),而不是“'”。另外,我不确定您对这些美元符号的用途是什么,但可能是您正在使用 clojuregensym用于卫生的便捷快捷方式。但是在使用它的每个标识符(so [f#],not [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=> 
于 2012-06-11T20:07:14.063 回答
3

也许这只是一个宏观练习,但是定义中间件函数的具体例子并不好——你失去了中间件概念给你的很多灵活性。例如,为什么要评估(f (+ 2 x))而不是评估(+ 2 (f x))?两者都是包装此函数的明智方法,您的语法无法描述后者。真的只是定义一个函数返回函数是灵活、简单、容易的;这个宏几乎没有带来任何好处。

于 2012-06-12T04:16:52.767 回答