As we should know, Clojure's map
can be applied to a sequence:
(map #(* %1 %1) [1 2 3]) ; (1)
..or to more than one, in this way:
(map vector [0 1] [2 1]) ; (2)
;=> ([0 2] [1 1])
Now I want to obtain the same result as (2), but I have the arguments stored inside a sequence. In other words, the following does not give the desired result:
(map vector [[0 1] [2 1]]) ; (3)
;=> ([[0 1]] [[2 1]])
So I've written this simple macro, where umap stands for "unsplice map":
(defmacro umap [fun args-list]
"umap stands for unspliced map.
Let args-list be a list of args [a1 a2 ... an].
umap is the same of (map fun a1 a2 .. an)"
`(map ~fun ~@args-list))
Obviously it works like a charm:
(umap vector [[0 1] [2 1]]) ; (4)
;=> ([0 2] [1 1])
So here's my question: am I reinventing the wheel? Is there another way to do the same as (4)?
Bye and thanks in advance,
Alfredo
apply
unpacks all of the elements in the sequence at the end of the argument list.
user> (apply map vector [[0 1] [2 1]])
([0 2] [1 1])
It's not at all obvious that your umap
works like a charm. In fact it will only work if you have the argument vector as a literal at compile time - which is exactly the times you could have passed multiple arguments to map
anyway!
user> (umap vector [[1 2] [1 2]])
([1 1] [2 2])
user> (let [args [[1 2] [1 2]]]
(umap vector args))
java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
[Thrown class java.lang.RuntimeException]
The macro only has access to the symbol args
because it runs at compile time, and can't splice it in order to use map. The right answer is to use apply
, which treats its last argument as a sequence, and splices it into a series of additional arguments to the given function:
user> (let [args [[1 2] [1 2]]]
(apply map vector args))
([1 1] [2 2])
我错过了什么,或者mapcat是否适合您的需求?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.