0
votes

I'm trying to write my second macro but I'm completely stuck here.

I would like to avoid writing everytime (vec (for [...])) so I'm trying to write a forv macro like filterv, mapv, etc. I work mostly with vectors in my programs since I need to have access to the index because I use external buffers/descriptors to fasten matrix process. I have written many ***v like functions (also adaptative functions like fmap )but I'm sticked with for.

So I wrote

(defmacro forv
  [seq-exprs body-expr]
  (vec (for (vec seq-exprs) body-expr)))

I tried with seq-exprs alone, it does not work. To be honest I tried also ~ and so on but I do not know how it works, I succeed in my first macro because it was far easier.

Clojure tell me that for requires a vector for binding.

Can someone help me and also explain what I am missing ? Thanks !

2
Can you elaborate a bit on why would you need to explicitly convert for return values to vectors? - OlegTheCat
I added teh explnation. The general is that I frequently need to have have acces to the index or by index for an algo. - Joseph Yourine
@nha's answer passes some pathological calls that @AlanThompson's detects. For example, given (forv '() 888), the former returns [], whereas the latter detects an error. - Thumbnail

2 Answers

1
votes

You could use the one built into the Tupelo Library. Source code is here: https://github.com/cloojure/tupelo/blob/master/src/tupelo/core.cljc#L181

(defmacro forv
  "Like clojure.core/for but returns results in a vector.  Equivalent to (into [] (for ...)). Not
   lazy."
  [& body]
  `(vec (for ~@body)))
0
votes
;;
;; you want something like that in the end: (forv [x (range 2)] x)  => (vec (for [x (range 2)] x))
;;

(defmacro forv
  [seq-exprs body-expr]
  `(vec (for [~@seq-exprs] ~body-expr)))
;;
;; check quote and unquote
;; in particular, check the tricky bit is https://clojuredocs.org/clojure.core/unquote-splicing
;;

Edit: I based my answer to mimic the original code in the question, but Alan's answer is better than mine.