I'm trying to write my first ever macro in Clojure. I want to mimic Ruby's %w{} operator, which works like this:
irb(main):001:0> %w{one two three}
=> ["one", "two", "three"]
I want to write a function similar in Clojure that returns a vector of words. Here is how it would look:
user=> (%w one two three)
=> ["one" "two" "three"]
I know this is something that cannot be defined as an ordinary function because the symbols would be evaluated before applying and we would see something like this:
user=> (%w one two three)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: one in this context, compiling:(NO_SOURCE_PATH:1:1)
Here is my attempt at a macro:
(defmacro %w [& words]
(map str (vec words)))
But it doesn't work.
user=> (%w one two three)
ClassCastException java.lang.String cannot be cast to clojure.lang.IFn user/eval801 (NO_SOURCE_FILE:1)
Why is this happening?
ANSWERS
So the problem was that the macro actually returned the correct output, but then the repl tried to evaluate it and "one" is not a valid function.
Thanks to the answers below, here are two correct macros that solve this problem:
(defmacro %w-vec [& words]
"returns a vector of word strings"
(mapv str (vec words)))
(defmacro %w-list [& words]
"returns a list of word strings"
(cons 'list (map str words)))