Clojure风格:调用';vec&x27;幂等还是冗余?

Clojure风格:调用';vec&x27;幂等还是冗余?,clojure,Clojure,我在一个应用程序中有一个函数foodeep,其目的是conj一个元素到一个连续集合的末尾。在其他功能中,这些集合是在很远的地方进行的。有时集合是向量,有时它们是列表或惰性序列,这是为了方便创建它们的函数。实际上,foo返回一个向量,该向量同样被其他下游函数使用,这些函数可能关心也可能不关心它们得到的是什么样的顺序集合 在连接新数据之前,很容易将foo的参数xs强制为带有(vec xs)的向量。我的问题是,如果xs碰巧已经是一个向量,或者vec及其被调用方是否“聪明”到足以绕过这种情况下的冗余分配

我在一个应用程序中有一个函数
foo
deep,其目的是
conj
一个元素到一个连续集合的末尾。在其他功能中,这些集合是在很远的地方进行的。有时集合是向量,有时它们是列表或惰性序列,这是为了方便创建它们的函数。实际上,
foo
返回一个向量,该向量同样被其他下游函数使用,这些函数可能关心也可能不关心它们得到的是什么样的顺序集合

在连接新数据之前,很容易将
foo
的参数
xs
强制为带有
(vec xs)
的向量。我的问题是,如果
xs
碰巧已经是一个向量,或者
vec
及其被调用方是否“聪明”到足以绕过这种情况下的冗余分配,我是否会支付一个可以避免的(可能是多项式)价格

如果
vec
的参数是
vector?
而不是
clojure.lang.IObj,则显示其最终调用
clojure.lang.lazlyPersistentVector/create
。在我寻找答案的过程中,我认为,提出一个关于设计意图的问题可能比深入挖掘未来可能发生变化的实现细节更明智。

我找到了一个涵盖该主题的解决方案,似乎是由Clojure语言开发人员编写的。重要的部分是:

在…上调用
vec

IPersistentVector-如果它已经是一个向量,请删除meta并返回一个新实例。如上所述,这种情况经常发生,现在是一种快速的恒定时间操作,而不是线性时间操作

除非我遗漏了一些上下文,否则这似乎表明
vec
已经过优化(截至2015年1月),在已经是向量的集合上是一个固定时间操作

为了完整性,我使用运行测试(感谢@Thumbnail的想法)。我在Surface Pro 4上运行了它,它有一个M3处理器,非常弱。预计你的时间会短得多:

(let [small-v (into [] (range 1000))
      large-v (into [] (range 1000000))]
  (do
    (c/bench (vec small-v))
    (println "-----")
    (c/bench (vec large-v))))
Evaluation count : 2902458480 in 60 samples of 48374308 calls.
             Execution time mean : 18.612868 ns ; <----------
    Execution time std-deviation : 1.153643 ns
   Execution time lower quantile : 17.731625 ns ( 2.5%)
   Execution time upper quantile : 22.199789 ns (97.5%)
                   Overhead used : 3.054999 ns

Found 6 outliers in 60 samples (10.0000 %)
    low-severe   6 (10.0000 %)
 Variance from outliers : 46.7497 % Variance is moderately inflated by outliers
-----
Evaluation count : 3122779260 in 60 samples of 52046321 calls.
             Execution time mean : 16.303825 ns ; <----------
    Execution time std-deviation : 0.614467 ns
   Execution time lower quantile : 15.727943 ns ( 2.5%)
   Execution time upper quantile : 17.949363 ns (97.5%)
                   Overhead used : 3.054999 ns

Found 5 outliers in 60 samples (8.3333 %)
    low-severe   1 (1.6667 %)
    low-mild     4 (6.6667 %)
 Variance from outliers : 23.8541 % Variance is moderately inflated by outliers
(让[small-v(进入[](范围1000))
大v(进入[](范围1000000))]
(做
(c/工作台(小型vec-v))
(println“--”)
(c/工作台(vec大v)))
评估计数:48374308个电话的60个样本中有2902458480个。

执行时间平均值:18.612868纳秒;每当我需要特定于向量的插入行为时,我都会使用
vec
,但我没有注意到它是一个瓶颈(即使是在我分析过的应用程序中)。我也没有真正推它,看看它是否在某一点上成为瓶颈。代码似乎没有这样做:
(让[x[1 2 3]](相同?x(vec x))
返回
false
@缩略图删除返回向量的元数据。在<代码>中是否考虑到这一点相同?
?我把它放在后面了。如果两个引用相同(将truthy返回到
相同?
),则它们指向相同的对象,因此具有相同的元数据。因此
(vec x)
是与
x
不同的对象。它在
x
的表示中占多少份额?我不知道。帮助标准证实了这一点
(bench(vec x))
返回了11 ns的平均值,对于
x
,作为10000长和1000万长的向量。在REPL上天真的计时给出了相反的结果。@很酷,谢谢您的测试。老实说,我完全依赖链接帖子。