beo*_*ver 5 protocols clojure reference-manual
让我说我写了一个函数:
(defn foo [to x] (conj to x))
Run Code Online (Sandbox Code Playgroud)
并希望通过声明to必须实现某些协议来记录它(因为在结构/类型中to必须支持该调用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))))
Run Code Online (Sandbox Code Playgroud)
不幸的是,协议直到Clojure 1.2才被引入,到那时,所有内置的数据结构抽象都已经被实现为Java接口而不是协议.这有你期望的缺点,但是当重新实现所有这些抽象作为协议适合ClojureScript,因为它是在引入协议之后创建的,将它们改进到JVM Clojure中是不可行的.
如果你查看源代码conj,你会看到它调用clojure.lang.RT/conj,这要求它的第一个参数实现IPersistentCollection接口.因此,您可以像这样编写函数:
(defn foo [to x]
{:pre [(instance? clojure.lang.IPersistentCollection to)]}
(conj to x))
Run Code Online (Sandbox Code Playgroud)
为了您的概括,我想指出你的问题,我问有关实现Clojure的核心接口了过去.如果答案不足以解决您的问题,请告诉我,我会在此处添加更多详细信息.
我会对你的invert-many-to-one功能做一些小的调整:
(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))))
Run Code Online (Sandbox Code Playgroud)
conj在一个地方指定为默认值.clojure.core/get只是get因为惯用而取而代之.当然,正如你在评论中指出的那样,这三个变化都有其自身的缺点,所以一定要带着它们.
| 归档时间: |
|
| 查看次数: |
183 次 |
| 最近记录: |