I'm trying to write a macro that builds middleware akin to that used in compojure.
I want to be able to call:
(def-middleware plus-two [x]
(+ 2 x))
And have the result look like:
(defn plus-two [f]
(fn [x]
(f (+ 2 x)))
I've got this far from reading on-line guides but it's not working out for me:
(defmacro def-middleware [fn-name args & body]
'(defn ~fn-name [f]
(fn ~args
(f ~@body))))
Any help or a pointer to a better macro writing guide would be great, thanks.
Let's see what macroexpand-1
gives us:
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))))
Not precisely what we're after! First things first: if you want to unquote things in a macro, you need to use "`" (the quasiquote/syntax-quote operator), not "'". Also, I'm not sure what you're after with those dollar signs, but it might be that you're going for the clojure's handy shortcut for using gensym
for hygiene. But you need it immediately after each identifier you use it with (so [f#]
, not [f]$
), and you need it on each occurrence of the identifier. And you don't need it with args
. Putting all this together:
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=>
Perhaps this is just a macro exercise, but the specific example of defining a middleware function is not good - you lose a lot of the flexibility that the middleware concept gives you. For example, why should this evaluate (f (+ 2 x))
instead of (+ 2 (f x))
? Both are sensible ways to wrap this function, and your syntax gives no way to describe the latter. Really just defining a function-returning-function is flexible, simple, and easy; this macro brings little to the table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With