当前位置 : 主页 > 大数据 > 区块链 >

哪个协议定义了clojure中的conj?

来源:互联网 收集:自由互联 发布时间:2021-06-22
让我说我写了一个函数: (defn foo [to x] (conj to x)) 并且希望通过声明必须实现某些协议来记录它(如在结构/类型中必须支持调用conj).是否有包含此信息的网站或数据库?显然,我想将这个问
让我说我写了一个函数:

(defn foo [to x] (conj to x))

并且希望通过声明必须实现某些协议来记录它(如在结构/类型中必须支持调用conj).是否有包含此信息的网站或数据库?显然,我想将这个问题概括为“我在哪里可以找到所有clojure协议的完整参考?”

作为使用Sam Estep的建议的一个明确而具体的例子,它看起来像:

(defn invert-many-to-one
  "returns a one-to-many mapping where vals are collections of type `(constructor-fn)`,
   (defaults to `hash-set`). Note that `constructor-fn` is a function of 0 args.
  `insert-fn` function can be passed. if only `constructor-fn` is passed
  then `insert-fn` defaults to `conj` and `(constructor-fn)` must be an instance
  of `clojure.lang.IPersistentCollection`"
  ([m] (invert-many-to-one hash-set conj m))
  ([constructor-fn m] {:pre [(instance? clojure.lang.IPersistentCollection (constructor-fn))]}
   (invert-many-to-one constructor-fn conj m))
  ([constructor-fn insert-fn m]
   (persistent!
    (reduce (fn [m [k v]]
              (assoc! m v (insert-fn (clojure.core/get m v (constructor-fn)) k)))
            (transient {}) m))))
不幸的是 protocols直到Clojure 1.2才被引入,到那时,所有内置的数据结构抽象都已经实现了 as Java interfaces而不是协议.这有你期望的缺点,但是当重新实现所有这些抽象作为协议适合ClojureScript,因为它是在引入协议之后创建的,将它们改进到JVM Clojure中是不可行的.

如果查看conj的源代码,您将看到它调用clojure.lang.RT/conj,这要求其第一个参数实现IPersistentCollection接口.因此,您可以像这样编写函数:

(defn foo [to x]
  {:pre [(instance? clojure.lang.IPersistentCollection to)]}
  (conj to x))

为了概括起见,我想指出一个question,我过去曾问过有关实现Clojure核心接口的问题.如果答案不足以解决您的问题,请告诉我,我会在此处添加更多详细信息.

我会对你的反转多对一功能进行一些小的调整:

(defn invert-many-to-one
  "Returns a one-to-many mapping where vals are collections of type
  `(constructor-fn)` (defaults to `hash-set`). Note that `constructor-fn` is a
  function of 0 args. `insert-fn` function can be passed. If only
  `constructor-fn` is passed then `insert-fn` defaults to `conj`.
  `(constructor-fn)` must be an instance of
  `clojure.lang.IPersistentCollection`."
  ([m]
   (invert-many-to-one hash-set m))
  ([constructor-fn m]
   (invert-many-to-one constructor-fn conj m))
  ([constructor-fn insert-fn m]
   {:pre [(instance? clojure.lang.IPersistentCollection (constructor-fn))]}
   (persistent!
    (reduce (fn [m [k v]]
              (assoc! m v (insert-fn (get m v (constructor-fn)) k)))
            (transient {}) m))))

>我改变了arity-1体,称为arity-2体,而不是arity-3体;这样,您只在一个地方指定conj作为默认值.
>我将前提条件移到了arity-3体中,以便在所有情况下使用它.
>我替换了clojure.core / get,只是为了获得惯用语.

当然,正如你在评论中指出的那样,这三个变化都有其自身的缺点,所以一定要带着它们.

网友评论