为了更好地理解 mapcat ,我举了一个例子:
user> (mapcat #(list % %) [1 2 3])
(1 1 2 2 3 3)
并试图重现文档所描述的用途, map 和 concat :
user> (doc mapcat)
clojure.core/mapcat
([f & colls])
Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection.
通过这样做:
user> (concat (map #(list % %) [1 2 3]))
((1 1) (2 2) (3 3))
然而,你可以看到它不起作用。但是我可以像这样使用reduce,但不知道它是否正确:
user> (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3]))
(1 1 2 2 3 3)
以上是有效的,但我不知道是否使用 map 和 concat 重新创建 mapcat 的功能。
基本上我想了解 mapcat 的工作原理。
发生了什么以及如何访问 mapcat 的来源? (我正在使用Emacs + nrepl)
答案 0 :(得分:6)
user=> (source mapcat)
(defn mapcat
"Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection."
{:added "1.0"}
[f & colls]
(apply concat (apply map f colls)))
nil
user=>
reduce
也有效的原因是因为它有效:
(concat (concat '(1 1) '(2 2)) '(3 3))
源代码中使用的 apply
扩展为:
(concat '(1 1) '(2 2) '(3 3))
使用concat
初次尝试:
user=> (map #(list % %) [1 2 3])
((1 1) (2 2) (3 3))
user=> (concat (list '(1 1) '(2 2) '(3 3)))
((1 1) (2 2) (3 3))
user=> (concat [1])
(1)
您可以看到,如果使用单个参数调用concat
,则会返回该参数。
答案 1 :(得分:2)
concat
是一个可变函数,即它可以采用n个参数,其中每个参数是一个值序列,即签名变为(defn concat [& lst]])
。在您的示例中,您使用单个参数调用concat,假设concat采用seq的seq值进行连接,这就是为什么您得到结果,即返回相同的列表列表。
(apply concat(apply map #(list % %) [1 2]))
不会工作。
(apply map #(list % %) [[1 2]])
或(apply map #(list % %) [1 2] [])
将有效。
这是因为apply要求最后一个参数是一个值序列,并且该值序列中的每个项目都将作为参数传递给应用函数。在您申请失败的情况下,呼叫将扩展为(map #(list % %) 1 2)
这是错误的,并且错误消息还显示它无法将长转换为序列,因为地图需要序列作为参数。