Clojure 多方法与协议

发布于 2024-12-14 16:44:58 字数 169 浏览 2 评论 0原文

我是一名 Clojure 新手,正在寻找一些何时使用协议以及何时使用多重方法的具体示例。我知道协议通常旨在创建类型层次结构和典型的 OOP 事物,它们是在多方法之后添加到语言中的,并且协议通常具有更好的性能,所以我的问题是:

协议是否旨在取代多方法?如果没有,你能给我一个例子,我将使用多种方法而不是协议吗?

I'm a Clojure novice and was looking for some concrete examples of when to use protocols and when to use multimethods. I know that protocols are generally geared towards creating a type hierarchy and typical OOP things, that they were added to the language after multimethods, and that protocols generally have better performance so my question is this:

Are protocols meant to replace multimethods? If not, could you give me an example where I would use multimethods instead of protocols?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谁把谁当真 2024-12-21 16:45:08

当您不需要类层次结构时,我喜欢多方法。例如,如果您有一个媒体数据库并且您的记录类似于 {:media-type :video, :bytes ...} 那么您可以有一个 multimethod

(defmulti make-grayscale :media-type)

然后您可以制作各种

; in video.clj
(defmethod make-grayscale :video [record]
  (ffmpeg ... (:bytes record))

; in photo.clj
(defmethod make-grayscale :photo [record]
  (imagemagick ... (:bytes record))

这样您可以避免有一个中心 cond 表达式,因此您可以获得类的模块化。但您不必经历所有“包装类层次结构”样板,这对我来说是一个应该留给 Java 世界的祸根。多方法只是函数,对我来说感觉更简洁。

I like multimethods when you don't otherwise need a class hierarchy. For example if you have a media database and your records are like {:media-type :video, :bytes ...} then you can have a multimethod

(defmulti make-grayscale :media-type)

Then you can make various

; in video.clj
(defmethod make-grayscale :video [record]
  (ffmpeg ... (:bytes record))

; in photo.clj
(defmethod make-grayscale :photo [record]
  (imagemagick ... (:bytes record))

That way you can avoid having a central cond expression, so you get the modularity of classes. But you don't have to go through all that "wrapper class hierarchy" boilerplate, which to me is a bane that should be left for the Java world. Multimethods are just functions and feel more clojuresque to me.

贱人配狗天长地久 2024-12-21 16:45:07

正如 Arthur 提到的,多种方法更强大,也更昂贵。事实上,协议可以被认为是多种方法的特例,其中调度函数是class。当然,实际情况并非如此,因为协议远不止这些。

如果您需要分派第一个参数的类以外的其他内容,则需要使用多种方法或重新设计。按类型调度是协议的一个很好的用例。

As mention by Arthur, multimethods are more powerful and more expensive. Indeed, protocols can be thought of as a special case of mutlimethods where the dispatch function is class. Of course, this is not really the case as protocols are more than that.

If you need to dispatch on something other than the class of the first argument, you'll need to use a multimethod, or redesign. Dispatching on type is a good use case for protocols.

寻找我们的幸福 2024-12-21 16:45:05

多种方法更强大且更昂贵,

在足够时使用协议,但如果您需要根据从火星看到的月相进行调度,那么多种方法是您的最佳选择。

协议的存在是为了让简单的东西保持简单,并为 clojure 提供一种生成与等效 java 几乎相同的字节码的方法。似乎大多数人大部分时间都在使用协议。当我需要分派多个参数时,我会使用多方法,尽管我必须承认这种情况只出现过一次,而且完整的 isa 层次结构的使用频率甚至更少(我)。简而言之,在需要时使用 Multimethods

以我的经验来看,最好的例子就在一开始,在 core.clj

Multimethods are more powerful and more expensive,

use protocols when they are sufficient but if you need to dispatch based on the phase of the moon as seen from mars then multimethods are your best choice.

Protocols exist to allow the simple stuff to stay simple and provide a way for clojure to generate very much the same bytecode that the equivalent java would. It seems that most people use protocols most of the time. I use multimethods when I need to dispatch on more than one argument, though I have to admit that this has only come up once, and full isa hierarchies are used even less often (by me). so in short use Multimethods when you need them

the best example In my expierence is right at the start, in core.clj

桜花祭 2024-12-21 16:45:03

协议和多方法是互补的,适用于略有不同的用例。

  • 协议根据第一个参数的类型提供高效的多态调度。由于能够利用一些非常高效的 JVM 功能,因此协议可以为您提供最佳性能
  • 多方法支持非常灵活的多态性,可以根据方法参数的任何函数进行调度。多种方法速度较慢,但​​非常灵活

一般来说,我的建议是使用协议,除非您有需要多种方法的特定情况。

您可能需要多方法的情况如下所示:

(defn balance-available? [amount balance] (> balance amount))

(defmulti withdraw balance-available?)

(defmethod withdraw true [amount balance] 
  (- balance amount))

(defmethod withdraw false [amount balance] 
  (throw (Error. "Insufficient balance available!")))

请注意,由于以下两个原因,您不能在此处使用协议:

  • 调度函数需要使用两个参数来确定要使用哪个方法实现(即,它是一个多方法实现)派遣案例)。
  • 您也无法区分第一个参数的类型(大概始终是数值)

Protocol and multimethods are complementary and intended for slightly different use cases.

  • Protocols provide efficient polymorphic dispatch based on the type of the first argument. Because the is able to exploit some very efficient JVM features, protocols give you the best performance.
  • Multimethods enable very flexible polymorphism which can dispatch based on any function of the method's arguments. Multimethods are slower but very flexible

In general, my advice is to use protocols unless you have a specific case that requires multimethods.

A case where you could require multimethods is something like the following:

(defn balance-available? [amount balance] (> balance amount))

(defmulti withdraw balance-available?)

(defmethod withdraw true [amount balance] 
  (- balance amount))

(defmethod withdraw false [amount balance] 
  (throw (Error. "Insufficient balance available!")))

Note that you can't use protocols here for both of the following reasons:

  • The dispatch function needs to use both arguments to determine which method implementation to use (i.e. it is a multiple dispatch case).
  • You also can't distinguish on the type of the first argument (which is presumably always a numeric value)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文