[英]why are `disj` and `dissoc` distinct functions in Clojure?
就我所见,Clojure的核心功能几乎总是适用于不同类型的收集,例如, conj
, first
, rest
等。我有点疑惑为什么disj
和dissoc
不同; 他们有完全相同的签名:
(dissoc map) (dissoc map key) (dissoc map key & ks)
(disj set) (disj set key) (disj set key & ks)
和相当类似的语义。 为什么这些都不是由同一个功能覆盖? 我可以看到支持这一点的唯一一个参数是map有(assoc map key val)
和(conj map [key val])
来添加条目,而sets只支持(conj set k)
。
我可以编写一个单行函数来处理这种情况,但是Clojure在很多时候都是如此优雅,以至于每当它不是:)时它真的很刺激我
只是为了给Arthur的答案提供一个平衡点: conj
甚至更早定义(名称conj
出现在core.clj的第82行vsp44的disj
和1429的dissoc
),但适用于所有Clojure集合类型。 :-)显然它不使用协议 - 相反它使用常规Java接口,就像大多数Clojure函数一样(事实上我相信目前Clojure中唯一使用协议的“核心”功能是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
“d”。
现在,理论上可以使用dissoc
来处理集合,但是也许有人可能会期望它们也支持assoc
,这可能说得不合理。 可能值得指出的是,向量确实支持assoc
而不是dissoc
,所以这些并不总是在一起; 这里肯定有一些审美紧张。
尽管我强烈怀疑这是core.clj中的一个引导问题,但尝试回答其他人的动机总是令人怀疑。 这两个函数都是在core.clj中很早就定义的,除了它们各自只采用一种类型并直接在其上调用方法之外几乎相同。
(. clojure.lang.RT (dissoc map key))
和
(. set (disjoin key))
这两个函数都是在core.clj
中定义protocal之前定义的 ,因此它们不能使用协议根据类型在它们之间进行分派。 这两个都存在于协议之前的语言规范中。 它们也经常被呼叫,以便有尽可能快地制作它们的强烈动机。
(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)))
谁在乎? 只需使用上面的功能,忘记过去......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.