(doseq [e coll1]
(myfunc e))
Run Code Online (Sandbox Code Playgroud)
非常快,如果你关心的都是副作用.如果我想myfunc"并行"从多个集合中获取元素,即应用于myfunc每个集合的第一个元素,然后应用于所有第二个元素,然后应用于所有第三个元素等,该怎么办?请注意,这同样是关于foras 的功能的问题doseq,但是如果想要一个序列作为输出,那么map就会做所需的事情,所以for没有必要.
(doseq [e1 coll1
e2 coll2]
(myfunc e1 e2))
Run Code Online (Sandbox Code Playgroud)
将改为应用于myfunc两个集合中所有可能的元素组合.如果我事先知道集合的元素是什么,我可以使用:when测试来仅合并某些元素,但是假设我不知道这个?
一种解决方案是创建ntuples以避免使用笛卡尔积,但这非常耗时,从而消除doseq了首先使用的速度优势:
(let [argvecs (map vector coll1 coll2)] ; seq of ntuples of interleaved vals
(doseq [args argvecs]
(apply myfunc args))))
Run Code Online (Sandbox Code Playgroud)
(这可能比单个集合慢大约8 doseq倍.查看此问题的时间domap1和domap17结尾.)
问题:如何&在宏中处理catch-all参数,当要传递的参数是序列时,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)))))
Run Code Online (Sandbox Code Playgroud)
我已经意识到这不是一个好的写作方式domap- 我在这个问题上得到了很好的建议.但是,我仍然想知道我在这个过程中遇到的棘手的宏问题.
如果集合作为文字传递,则此方法有效:
user=> (domap println [0 1 2])
0
1
2
nil
Run Code Online (Sandbox Code Playgroud)
但是在这样的其他情况下不起作用:
user=> (domap println (range 3))
range
3
nil
Run Code Online (Sandbox Code Playgroud)
或者这一个:
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)
Run Code Online (Sandbox Code Playgroud)
问题是它是文字表达式colls …