就我所见,Clojure的核心功能几乎总是适用于不同类型的收藏,例如: conj
,first
,rest
等。我有点疑惑disj
和dissoc
为何不同;他们有完全相同的签名:
(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在很多时候非常优雅,只要它不是,它就会对我很不利:)
答案 0 :(得分:7)
为了给Arthur的答案提供一个平衡点:conj
甚至更早定义(名称conj
出现在core.clj的第82行vs.1443 disj
和{14} for { {1}})但适用于所有Clojure集合类型。 :-)显然它不使用协议 - 而是使用常规Java接口,就像大多数Clojure函数一样(事实上我相信目前Clojure中唯一使用协议的“核心”功能是dissoc
/ reduce
)。
我猜想这是由于审美选择,实际上可能与地图支持reduce-kv
的方式有关 - 他们是否支持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
可以在集合上工作,但是也许有人可能会期望它们也支持dissoc
,这可能说得不合理。值得指出的是,向量确实支持assoc
而不是assoc
,所以这些并不总是在一起;这里肯定有一些审美紧张。
答案 1 :(得分:4)
(. clojure.lang.RT (dissoc map key))
和
(. set (disjoin key))
在core.clj
中定义protocals 之前定义了这两个函数,因此它们不能使用协议根据类型在它们之间进行分派。这两个都存在于协议之前的语言规范中。它们也经常被呼叫,以便有尽可能快地制作它们的强烈动机。
答案 2 :(得分:1)
(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)))
谁在乎?只需使用上面的功能,忘记过去......