作为一个练习,我正在尝试重新实现zipmap。以下语句工作正常,它获取键和值并将它们转换为映射:
user=> (into {} (mapv vector [:a :b] [1 2]))
{:a 1, :b 2}但是,当我试图将上述语句转换为函数时,会遇到问题:
user=> ((fn [& xs] (into {} (mapv vector xs))) [:a :b] [1 2])
IllegalArgumentException Vector arg to map conj must be a pair
Clojure.lang.ATransientMap.conj (ATransientMap.java:37)我的实施有什么问题,为什么会发生?
发布于 2017-11-27 18:15:12
您可以通过使用apply将xs应用于mapv vector来使示例工作。
((fn [& xs] (into {} (apply mapv vector xs))) [:a :b] [1 2])这是由于变量参数是如何绑定到xs的。如果没有apply,本质上就是像这样调用(mapv vector [[:a :b] [1 2]]),但希望它像(mapv vector [:a :b] [1 2])一样被调用。
发布于 2017-11-27 19:18:04
问题在于如何获取匿名函数的参数。
[& xs]将将参数卷到列表中
因此,在您的非函数版本(into {} (mapv vector [:a :b] [1 2]))中,您是在两个集合上映射向量
在您的函数版本中,您是在one集合上映射向量,基本上是这样做的:
(into {} (mapv vector [[:a :b] [1 2]])),它的计算结果是(into {} [[[:a :b] [1 2]]]]),它会给出一个错误
可能的解决方案
既然您正在尝试重新实现zipmap,为什么不使用与[keys vals]而不是[& xs]相同的arg列表,并编写如下函数:
((fn [keyz valz] (into {} (mapv vector keyz valz))) [:a :b] [1 2])
您还可以自己展开集合:
((fn [& xs] (into {} (mapv vector (first xs) (second xs)))) [:a :b] [1 2])
我认为使用显式arg列表是一种更精确的方法,因为您希望获得两个特定的集合
https://stackoverflow.com/questions/47517056
复制相似问题