为什么键和值不能用于向量?

时间:2016-02-11 14:26:20

标签: vector clojure

我经常发现自己处于这样一种情况:我真的不在乎是否有矢量或地图:

[:foo :bar :baz :qux]
{0 :foo, 1 :bar, 2 :baz, 3 :qux}

重要的功能(getassoc等)适用于两者。有些人,比如dissoc,不会在矢量上工作,但他们有充分的理由不这样做。

但是,我根本不理解为什么keysvals在地图上工作而不在上。有没有什么好的理由可以解释为什么他们没有像这样实现(或者更优雅的多态解决方案)呢?

(defn keys [m]
  (if (vector? m)
    (seq (range (count m)))
    (clojure.lang.RT/keys m)))

(defn vals [m]
  (if (vector? m)
    (seq m)
    (clojure.lang.RT/vals m)))

如果没有充分理由,我怎样才能尝试在标准Clojure中实现?

2 个答案:

答案 0 :(得分:5)

我认为这是一个有效的想法。

应该使用哪些函数以及哪些函数应该是错误的问题很难划清界限。一方面,语言可能过于宽松(JavaScript?),以至于它可以让你伤害自己。在另一端,它可能是如此规范,你没有强大的抽象组成(C?)。

在这种特殊情况下,我们正在讨论在编写需要映射的代码时发现错误的能力,但是传递了一个向量;反对能够编写更多通用代码的好处。我个人认为它被视为一个错误,因为我有时会将错误类型的集合传递给一个函数,并且更喜欢它而不是做某事。

我会发现在向量上调用keys会让人感到困惑,因为向量没有键,它是可索引的。对我来说,他们是不同的东西。因此,如果我在向量上编写调用keys的代码,则可能是错误。如果我真的想要一个与向量计数大小相同的范围,我会明确地写出来。如果我想要一个可以处理地图和向量的函数,我会使用条件类型来选择键或范围计数。显然这些只是我的偏好,但对我来说,它们是不希望keys处理向量的重要原因。具体来说,原因是我想发现错误。

然而,完全可以理解你更喜欢它使用向量,看它们是通过索引关联的。

至于dissoc是否应该工作,其他人可能会声称为什么不呢? (dissoc [1 2 3] 0) -> [2 3])存在性能问题,因为您无法删除O(1)中的元素,如果Clojure采用rbb-vector则不会。有时你必须做这个操作非常方便。它是something people need to do,在Clojure中非常丑陋和不透明!我们俩都不希望这是一个功能,但我敢打赌它在某些情况下会非常优雅。但它并不是一个技术限制的例子,我们只是喜欢它。

Clojure有一个开放的contribution过程,归结为: 在Clojure Dev Google小组讨论您正在尝试与其他人做些什么。他们可能会提供意见和建议,从而带来更高质量的变更和更顺畅的提交流程。提交CA后,您可以通过JIRA提交补丁。

任何人都可以向Clojure提交错误或增强请求。 任何签署了贡献者协议的人都可以提供补丁或改进门票。 筛选员已被授予通过(部分)过程阶段移动票证的能力。 BDFL - Rich Hickey是Clojure内容的创造者和仁慈的独裁者。 Stuart Halloway也有特殊级别的访问权限,通常会向Clojure提交补丁。

如果您认为这对Clojure来说是一个很好的改变,我建议首先在Clojure Group中讨论它,以获得对该想法的一些支持,然后将其带到Clojure Dev Group。一般来说,当有支持文物时,你的想法最好收到,例如"这是一个很好的用例,它展示了价值"和"在这里讨论其他人渴望相同的价值主张"。

答案 1 :(得分:1)

As background re the collection model: http://insideclojure.org/2016/03/16/collections/

Keys and vals are both defined as functions that take a seqable of map entries. Given that definition, it is not easily possible to widen it to also take a collection with the associative trait, because a collection like vector will not produce a seq of entries, but rather a seq of vector values. The ability to seq to map entries is something only provided by maps.

Yes, it would be possible to make a function that worked on either, but I think doing so would break the existing contract of these functions, not extend it.

To the design question of whether it should have been done this way or not in the first place, that's harder for me to say.