覆盖键和值

时间:2017-07-22 21:51:08

标签: clojure interface

给出类型:

(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);
    }
...

似乎keysvals依赖于seq clojure.lang.Seqable的实施。它只需要clojure.lang.MapEntry返回的(seq r)对中的第一个/第二个值。

有什么方法吗?

1 个答案:

答案 0 :(得分:3)

不,无法覆盖clojure.core/keysclojure.core/vals的此行为。如您所述,那些Clojure functions会调用clojure.lang.RT中的相应static methodsKeySeq会调用ValSeqclojure.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映射的属性,但不适用于您定义的多映射。由你来决定语义的调整是否是一个好主意。