mik*_*era 10 abstraction protocols clojure
假设我有两个协议:
(defprotocol A
(f [this]))
(defprotocol B
(g [x y]))
Run Code Online (Sandbox Code Playgroud)
我想将协议B扩展到支持协议A的所有实例:
(extend-protocol A
String
(f [this] (.length this)))
(extend-protocol B
user.A
(g [x y] (* (f x) (f y))))
Run Code Online (Sandbox Code Playgroud)
主要动机是避免必须将B分别扩展到A可能扩展到的所有可能的类,或者甚至是其他人可能扩展到A的未知未来类(例如,如果A是公共API的一部分,例如) .
但是这不起作用 - 你会得到如下内容:
(g "abc" "abcd")
=> #<IllegalArgumentException java.lang.IllegalArgumentException:
No implementation of method: :g of protocol: #'user/B found for
class: java.lang.String>
Run Code Online (Sandbox Code Playgroud)
这有可能吗?如果没有,是否有一个合理的解决方法来实现相同的目标?
协议不是类型,不支持继承.协议本质上是一个命名的函数定义集合(以及调用这些函数时的调度机制).
如果您有多个类型都碰巧具有相同的实现,您可以简单地调用一个公共函数.或者,您可以使用该地图创建方法地图和extend每种类型.例如:
(defprotocol P
(a [p])
(b [p]))
(deftype R [])
(deftype S [])
(deftype T [])
(def common-P-impl
{:a (fn [p] :do-a)
:b (fn [p] :do-b)})
(extend R
P common-P-impl)
(extend S
P common-P-impl)
(extend T
P common-P-impl)
如果您提供有关实际情况的更多详细信息,我们可能会建议正确的方法.
在我看来,你可以实现的功能g在以下方面f.如果是这种情况,您将拥有所需的所有多态性,而无需协议B.
我的意思是以下,因为这f是多态的,然后
(defn g [x y]
(* (f x) (f y)))
Run Code Online (Sandbox Code Playgroud)
产生一个g支持实现协议的所有类型的函数A.
通常,当协议位于最底层时,仅根据协议功能(或者自身使用协议的其他功能)定义的简单功能使得整个命名空间/库/程序非常多态,可扩展且灵活.
序列库就是一个很好的例子.简化后,有两个多态函数,first和rest.序列库的其余部分是普通函数.
| 归档时间: |
|
| 查看次数: |
2226 次 |
| 最近记录: |