Clojure宏从函数构建更高阶函数

jdo*_*oig 5 macros clojure

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

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

ben*_*n w 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))))
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)