【发布时间】:2014-02-04 03:22:53
【问题描述】:
问题:宏中&之后的catch-all参数,当传递的参数是序列时,catch-all变量需要作为序列的序列处理?包罗万象的变量中列出的是文字表达式。
这是一个宏,旨在大致表现 Common Lisp 的 mapc,即做 Clojure 的 map 所做的,但仅用于副作用,并且没有懒惰:
(defmacro domap [f & colls]
`(dotimes [i# (apply min (map count '(~@colls)))]
(apply ~f (map #(nth % i#) '(~@colls)))))
我开始意识到这不是写domap 的好方法——我在this 问题中得到了很好的建议。但是,我仍然想知道我在此过程中遇到的棘手的宏观问题。
如果集合作为文字传递,则此方法有效:
user=> (domap println [0 1 2])
0
1
2
nil
但在像这样的其他情况下不起作用:
user=> (domap println (range 3))
range
3
nil
或者这个:
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)
问题在于colls 中的文字表达式。这就是为什么宏 domap 在传递整数序列时有效,但在其他情况下无效。注意'(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# 等的各种组合。没有任何效果。尝试将其编写为宏可能是一个错误,但我仍然很好奇如何编写一个接受此类复杂参数的可变参数宏。
【问题讨论】: