我是否重新发明了(方形)轮子?

时间:2011-04-08 16:11:22

标签: macros map clojure

我们应该知道,Clojure的map可以应用于序列:

(map #(* %1 %1) [1 2 3])           ; (1)

..或以多种方式,以这种方式:

(map vector [0 1] [2 1])           ; (2)
;=> ([0 2] [1 1])

现在我想获得与(2)相同的结果,但我将参数存储在序列中。换句话说,以下内容未给出所需的结果:

(map vector [[0 1] [2 1]])         ; (3)
;=> ([[0 1]] [[2 1]])

所以我写了这个简单的宏,其中umap代表“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))

显然它就像一个魅力:

(umap vector [[0 1] [2 1]])        ; (4)
;=> ([0 2] [1 1])

所以这是我的问题:我是否重新发明轮子? 还有另一种方法可以像(4)那样做吗?

再见,谢谢,

阿尔弗雷

3 个答案:

答案 0 :(得分:13)

apply解包参数列表末尾序列中的所有元素。

user> (apply map vector [[0 1] [2 1]])
([0 2] [1 1])

答案 1 :(得分:8)

你的umap就像魅力一样,显然并不明显。事实上,只有在编译时将参数向量作为文字时才会起作用 - 这正是你可以将多个参数传递给map的时间!

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]

宏只能访问符号 args,因为它在编译时运行,并且无法拼接它以使用map。正确的答案是使用apply,它将其最后一个参数视为一个序列,并将其拼接成给定函数的一系列附加参数:

user> (let [args [[1 2] [1 2]]]
        (apply map vector args))
([1 1] [2 2])

答案 2 :(得分:0)

我是否遗漏了某些内容,或mapcat是否符合您的需求?