0

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?

2
  • 1
    This is not possible, see stackoverflow.com/q/20677055 and stackoverflow.com/q/32453062. Commented Dec 2, 2017 at 13:54
  • 1
    No user reader macros in Clojure. Something similar looking could be done with tagged literals. Otherwise #(do [(inc %1) %2]) Commented Dec 2, 2017 at 22:38

1 Answer 1

1

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 ArityExceptions, 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]) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.