【问题标题】:why are `disj` and `dissoc` distinct functions in Clojure?为什么 `disj` 和 `dissoc` 在 Clojure 中有不同的功能?
【发布时间】:2015-03-04 00:31:19
【问题描述】:

据我所知,Clojure 的核心功能几乎总是适用于不同类型的集合,例如conjfirstrest 等等。我有点疑惑为什么disjdissoc 是不同的;它们具有完全相同的签名:

(dissoc map) (dissoc map key) (dissoc map key & ks)
(disj set) (disj set key) (disj set key & ks)

和相当相似的语义。为什么这些都没有被相同的功能覆盖?我能看到的唯一支持这一点的论点是地图同时具有(assoc map key val)(conj map [key val]) 来添加条目,而集合仅支持(conj set k)

我可以编写一个单行函数来处理这种情况,但是 Clojure 很多时候都非常优雅,以至于当它不是时它真的让我感到不安:)

【问题讨论】:

    标签: clojure


    【解决方案1】:

    只是为了抵消 Arthur 的回答:conj 的定义更早(名称 conj 出现在 core.clj 的第 82 行,而 disj 的名称为 1443,dissoc 的名称为 1429),但仍然有效在所有 Clojure 集合类型上。 :-) 显然它不使用协议——而是使用常规的 Java 接口,就像大多数 Clojure 函数一样(事实上,我相信目前 Clojure 中唯一使用协议的“核心”功能是reduce/@ 987654326@).

    我猜想这是出于审美选择,实际上可能与地图支持conj 的方式有关——如果他们支持disj,人们可能会期望它采用与可能相同的论点传递给conj,会出现问题:

    ;; hypothetical disj on map
    (disj {:foo 1
           [:foo 1] 2 
           {:foo 1 [:foo 1] 2} 3}
           }
          {:foo 1 [:foo 1] 2} ;; [:foo 1] similarly problematic
          )
    

    应该返回{}{:foo 1 [:foo 1] 2} 还是{{:foo 1 [:foo 1] 2} 3}conj 愉快地接受 [:foo 1]{:foo 1 [:foo 1] 2} 作为 conj 在地图上的东西。 (conj 带有两个映射参数意味着merge;实际上merge 是根据conj 实现的,添加了对nil 的特殊处理。

    因此,将 dissoc 用于映射也许是有意义的,这样很明显它会删除一个键,而不是“可能是 conj'd 的东西”。

    现在,理论上 dissoc 可以在集合上工作,但也许人们可能期望它们也支持 assoc,这可以说是没有意义的。可能值得指出的是,向量确实支持assoc 而不是dissoc,所以它们并不总是在一起;这里肯定存在一些审美张力。

    【讨论】:

      【解决方案2】:

      试图回答他人的动机总是令人怀疑的,尽管我强烈怀疑这是 core.clj 中的一个引导问题。这两个函数都在 core.clj 的早期定义并且几乎相同,只是它们都只采用一种类型并直接调用它的方法。

      (. clojure.lang.RT (dissoc map key))
      

      (. set (disjoin key))
      

      这两个函数都是在core.clj在定义协议之前定义的,因此它们不能使用协议根据类型在它们之间进行调度。在协议存在之前,这两者也在语言规范中定义。他们也经常被调用,以至于有强烈的动机让他们尽可能快。

      【讨论】:

        【解决方案3】:
          (defn del
           "Removes elements from coll which can be set, vector, list, map or string"
           [ coll & rest ]
          (let [ [ w & tail ] rest  ]
            (if w 
              (apply del (cond
                  (set? coll) (disj coll w)
                  (list? coll)  (remove #(= w %) coll)
                  (vector? coll) (into [] (remove #(= w % ) coll))
                  (map? coll) (dissoc coll w)
                  (string? coll) (.replaceAll coll (str w) "")) tail)
                    coll)))
        

        谁在乎?只需使用上面的功能,忘记过去......

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-09
          • 1970-01-01
          • 2021-11-14
          • 1970-01-01
          • 2021-06-03
          相关资源
          最近更新 更多