Clojure variable macro repeating over sequences compiled in & optional parameter

Problem: how to handle the catch-all parameter after &in a macro when the arguments passed are sequences and the catch-all variable should be treated as a sequence of sequences? What gets into the catch-all variable are literal expressions.

This is a macro that should behave roughly Common Lisp mapc, i.e. do what Clojure does map, but only for side effects and without laziness:

(defmacro domap [f & colls] 
      `(dotimes [i# (apply min (map count '(~@colls)))]
         (apply ~f (map #(nth % i#) '(~@colls)))))

I realized that this is not a very good way to write domap- I got good advice about this in this matter. However, I am still wondering about the complex macro problem that I encountered along the way.

This works if the collection is passed as a literal:

user=> (domap println [0 1 2])
0
1
2
nil

But does not work in other situations like this:

user=> (domap println (range 3))
range
3
nil

Or this one:

user=> (def nums [0 1 2])
#'user/nums
user=> (domap println nums)
UnsupportedOperationException count not supported on this type: Symbol clojure.lang.RT.countFro (RT.java:556)

The problem is that these are literal expressions that are inside colls. This is why a macro domapworks when a sequence of integers is transmitted, but not in other situations. Pay attention to the examples '(nums):

user=> (pprint (macroexpand-1 '(domap println nums)))
(clojure.core/dotimes
 [i__199__auto__
  (clojure.core/apply
   clojure.core/min
   (clojure.core/map clojure.core/count '(nums)))]
 (clojure.core/apply
  println
  (clojure.core/map
   (fn*
    [p1__198__200__auto__]
    (clojure.core/nth p1__198__200__auto__ i__199__auto__))
   '(nums))))

~, ~@, ', let var# .. . , , , , , , .

+3
1

:

'(~@colls) . E. g. (range 3), '((range 3)), , (range 3), , , .

, (~@colls) , , , , ((range 3)), ( ((0 1 2))).

list, :

(defmacro domap [f & colls]
  `(dotimes [i# (apply min (map count (list ~@colls)))]
     (apply ~f (map #(nth % i#) (list ~@colls)))))

=> (domap println (range 3))
0
1
2

: . :

(defmacro domap [f & colls]
  `(let [colls# (list ~@colls)]
     (dotimes [i# (apply min (map count colls#))]
       (apply ~f (map #(nth % i#) colls#)))))

- , , . - (fn [& args] ...) f, .

, , . , , eval'd - . , :

(defn domap [f & colls]
  (dotimes [i (apply min (map count colls))]
    (apply f (map #(nth % i) colls)))) 

, , , , , dorun, seq, head. E. g.:

`(dorun (map println (range 3)))

.

, dorun map, comp :

(def domap (comp dorun map))

=> (domap println (range 3) (range 10) (range 3))

0 0 0
1 1 1
2 2 2
+5

All Articles