如何实现Clojure函数对任意数量向量逐元素应用指定函数?
实现支持任意数量向量的元素级函数应用
假设我有两个向量:
(def x [1 2 3]) (def y [4 5 6])
我想要对这些向量的每个元素依次应用一个函数(例如+),写了这样的函数:
(defn mapply [x y] (map + x y))
这个函数运行正常,输出结果是(5 7 9)。现在我希望实现更通用的功能,让该函数能够处理任意数量的向量。
最初尝试用&参数接收所有向量:
(defn mapply [& vecs] (map + vecs))
这段代码运行报错:
Cannot cast clojure.lang.PersistentVector to java.lang.Number
我知道需要把vecs拆成单独的向量,但不知道怎么在数量不确定的情况下正确解构。后来又试了用apply展开:
(defn mapply [& vecs] (apply (fn [& stuff] (map + stuff)) vecs))
但这段代码和之前的错误写法本质上没区别,还是不行。请问该怎么实现这个能接受任意数量向量的函数?
解决方法
核心是利用apply把接收的向量序列展开为map的多个参数,正确写法如下:
(defn mapply [& vecs] (apply map + vecs))
原理解释
map本身就支持传入多个集合参数,它会依次从每个集合中取出对应位置的元素,传递给第一个参数指定的函数执行。比如(map + x y)就是分别从x和y中取同位置元素相加。- 当用
& vecs接收任意数量的向量时,vecs是一个包含所有传入向量的序列。apply map + vecs会把vecs里的元素逐个展开,作为map的后续参数,等价于手动写(map + vec1 vec2 vec3 ...),完美适配map的多集合处理逻辑。
测试验证:
(mapply [1 2 3] [4 5 6] [7 8 9]) ; 输出结果:(12 15 18)
如果想要让函数更通用,支持任意元素级操作,可以把操作函数也作为参数传入:
(defn element-wise [f & vecs] (apply map f vecs))
这样就能灵活使用不同的元素级函数:
(element-wise * [1 2 3] [4 5 6] [2 3 4]) ; 输出结果:(8 30 72)
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

