给出类型:
(defn as-pairs [m]
(when-not (empty? m)
(seq (persistent! (reduce (fn [s [k vs]]
(reduce (fn [s v] (conj! s (clojure.lang.MapEntry/create k v))) s vs))
(transient []) m)))))
(deftype Rel [m]
clojure.lang.Seqable
(seq [this] (as-pairs m))
clojure.lang.ILookup
(valAt [this k] (get m k))
(valAt [this k default] (get m k default))
clojure.lang.IPersistentMap
(assoc [this k v] (Rel. (update m k #(conj (or % #{}) v))))
(assocEx [this k v] (throw (Exception.)))
(without [this k] (Rel. (dissoc m k))))
(defn relation [& pairs]
(reduce (fn [r [k v]] (assoc r k v)) (Rel. (hash-map)) pairs))
是否可以覆盖对(keys ...)
和(vals ...)
的来电?
例如,当前的实现
>(def r (relation [1 2] [1 3] [2 4]))
> r
{1 3, 1 2, 2 4}
> (get r 1)
#{3 2}
> (seq r)
([1 3] [1 2] [2 4])
> (keys r)
(1 1 2)
> (vals r)
> (3 2 4)
例如,我希望keys
返回更多(seq (set (keys r))
的内容,即排除重复内容。我可以看到in
static public class KeySeq extends ASeq{
final ISeq seq;
final Iterable iterable;
static public KeySeq create(ISeq seq){
if(seq == null)
return null;
return new KeySeq(seq, null);
}
...
似乎keys
和vals
依赖于seq
clojure.lang.Seqable
的实施。它只需要clojure.lang.MapEntry
返回的(seq r)
对中的第一个/第二个值。
有什么方法吗?
答案 0 :(得分:3)
不,无法覆盖clojure.core/keys
和clojure.core/vals
的此行为。如您所述,那些Clojure functions会调用clojure.lang.RT
中的相应static methods,KeySeq
会调用ValSeq
和clojure.lang.APersistentMap
类中的createFromMap
static methods IPersistentMap
。所有这些实现都直接使用keys
来获取它们的序列,因此它们不能独立于您已经编写的内容而被覆盖。
在这种情况下你可以做的一件事是提供你自己的clojure.core
函数来替换(ns example.core
(:refer-clojure :exclude [keys])
(:require [clojure.core :as clj]))
(defn keys [m]
(distinct (clj/keys m)))
中的那个:
(ns example.usage
(:refer-clojure :exclude [keys])
(:require [example.core :refer [keys]]))
(keys {:foo :bar :baz :qux})
;;=> (:foo :baz)
示例:
clojure.core/keys
需要注意的一点是,seq
合同的一部分是返回与(= m (zipmap (keys m) (vals m)))
匹配的序列,因此,例如,example.core/keys
一般都成立。这个Rails
函数满足常规Clojure映射的属性,但不适用于您定义的多映射。由你来决定语义的调整是否是一个好主意。