Reputation: 10075
I have come up with the below function, which works as intended but it uses eval which is horrible, and does not exist in ClojureScript where i intend to use it.
(defn path [d p]
(eval
(concat '[-> d]
(flatten (map
#(conj (repeat (dec %) 'z/right) 'z/down)
(path-to-vector p))))))
How would I convert it to a macro? My attempt looks like this:
(defmacro path [d p]
`(concat (-> ~d)
(flatten
(map #(conj (repeat (dec %) z/right) z/down)
(path-to-vector ~p)))))
But that clearly does not work.
Upvotes: 2
Views: 210
Reputation: 91554
Ankur is correct that this is a case for reduce and neither a macro or eval is appropriate, though it's perhaps still worth explaining the mechanics of writing a macro such as this for it's own sake:
Your macro example is very close, all you need is the splicing-unquote function to make it work:
(defmacro path [d p]
`(-> ~d
~@(flatten
(map #(conj (repeat (dec %) z/right) z/down)
(path-to-vector ~p)))))
this evaluates the call to flatten at macro expansion time and then concatenates it into the resulting s-expression/list.
Upvotes: 1
Reputation: 33637
No need for a macro or eval, the operation is just a reduce
:
(defn path [d p]
(reduce (fn [s v]
(reduce #(%2 %1) s (conj (repeat (dec v) z/right) z/down)))
d (path-to-vector p)))
Also note that (conj (repeat (dec %) z/right) z/down)
means z/down and then all the z/right coz repeate return a sequence, in case you want all z/right first and last item should be z/down then you should use (conj (vec (repeat (dec %)) z/right) z/down)
Upvotes: 4