Reputation: 28837
I want to write a Clojure vector macro form #[...]
I can use like #[(inc %1) %2]
that is equivalent to (fn [a b] [(inc a) b])
or #(vector (inc %1) %2)
.
Is this a special data reader, or can this be written with defmacro
?
Upvotes: 0
Views: 204
Reputation: 45750
Just for a laugh, I wrote up what is probably the closest you're going to come to a solution. It doesn't define a reader macro, but it does define a macro that almost allows for the syntax you're looking for.
I had to reinvent the wheel a bit to allow for %
style implicit parameters since I couldn't get abusing #()
to work:
(defn arg-list
"Returns a lazy-seq of (%, %2, %3, ...) strings."
([] (arg-list 1))
([n] (lazy-seq
(cons (str "%" (if (> n 1) n))
(arg-list (inc n))))))
(defmacro lambda
"Use as you would #(). (map (lambda (* % 2)) [1, 2, 3])"
[& body]
(let [arg-syms (->> (arg-list) (take 5) (mapv symbol))]
`(fn [& ~arg-syms]
~@body)))
This defines a regular macro that mimics the #()
reader macro. It evaluates to a variadic function that has the first 5 arguments in the list bound to "percentage" symbols. It allows for %
style parameters:
(mapv (lambda (* % %2)) [1 2 3] [1 5 9])
[1 10 27]
Then, you can just use that to define a macro that almost does what you're looking for:
(defmacro vec-f [& elems]
`(lambda (vec ~(vec elems))))
(mapv (vec-f (inc %) %2) [1 2 3] [1 5 9])
[[2 1] [3 5] [4 9]]
But I can't say that I recommend its use.
It doesn't lend itself to readability.
Instead of throwing ArityException
s, the missed arguments will just default to nil
via destructuring
It only allows up to %5
; although that's a hard-coded limit that can be increased. Using the current "var-arg method", I can't allow for an arbitrary number of parameters. Trying to realize an infinite list at compile time will obviously end in tears.
As a proof of concept though, it shows what you're after is almost possible.
You should just use
#(vector (inc %1) %2)
instead, or, as suggested in the comments
#(do [(inc %1) %2])
Upvotes: 1