10

看了Rich Hickey对Clojure 1.2协议的采访,对 Clojure 知之甚少,我有一些关于 Clojure 协议的问题:

  • 它们是否打算与Scala中的结构类型做同样的事情?协议相对于结构类型有什么好处(性能、灵活性、代码清晰度等)?它们是通过反射实现的吗?
  • 关于与 Scala 互操作性的问题:Scala 中可以使用协议代替结构类型吗?它们可以在 Scala 中扩展(如果“扩展”术语可以应用于协议)吗?
4

4 回答 4

15

完全不相关。

Scala 是一种静态类型语言。Clojure 是一种动态类型语言。这种差异从根本上塑造了它们。

结构类型是静态类型,周期。它们只是让编译器静态地证明一个对象将具有特定结构的一种方法(我在这里说证明,但强制转换会像往常一样导致虚假证明)。

Clojure 中的协议是一种创建动态调度的方法,它比反射或在地图中查找要快得多。从语义上讲,它们并没有真正扩展 Clojure 的功能,但在操作上它们比以前使用的机制要快得多。

Scala 特征更接近于协议,Java 接口也是如此,但同样存在静态与动态的问题。Scala 特征必须在编译时与类关联,类似于 Java 接口。Clojure 协议甚至可以由第三方在运行时添加到数据类型。

通过诸如包装器/代理模式或动态代理( http://download.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html)之类的机制,Java 和 Scala 中的 Clojure 协议之类的东西是可能的。但是这些将比 Clojure 协议笨拙得多,并且获得正确的对象身份也很棘手。

于 2010-12-22T15:48:47.560 回答
10

Clojure 中协议的目的是以有效的方式解决表达式问题。

[参见:clojure 协议的简单解释]

Scala 对表达式问题的解决方案是隐式。因此,从语义上讲,与 Scala 中的 Clojure 协议最接近。(在 Haskell 中,它可能是 Typeclasses 或 Type Families。)

于 2010-12-22T20:52:28.747 回答
6

正如我从这篇介绍性博文中了解到的那样,闭包协议更接近于 Scala Traits,而不是结构类型(因此,不能用作它们的替代品,回答我的第二个问题):

/* ----------------------- */
/* --- Protocol definition */
/* ----------------------- */

(defprotocol Fly
  "A simple protocol for flying"
  (fly [this] "Method to fly"))

/* --- In Scala */    
trait Fly{
    def fly: String
}

/* --------------------------- */
/* --- Protocol implementation */
/* --------------------------- */

(defrecord Bird [nom species]
  Fly
  (fly [this] (str (:nom this) " flies..."))

/* --- In Scala */    
case class Bird(nom: String, species: String) extends Fly{
    def fly = "%s flies..." format(nom)
}

/* --------------------- */
/* --- Dynamic extension */
/* --------------------- */

(defprotocol Walk
  "A simple protocol to make birds walk"
  (walk [this] "Birds want to walk too!"))

(extend-type Bird
  Walk
  (walk [this] (str (:nom this) " walks too..."))

/* --- In Scala */    
trait Walk{
    def walk = "Birds want to walk too!"
}

implicit def WalkingBird(bird: Bird) = new Walk{
    override def walk = "%s walks too..." format(bird.nom)
}

/* --------------- */
/* --- Reification */
/* --------------- */

(def pig (reify
                Fly (fly [_] "Swine flu...")
                Walk (walk [_] "Pig-man walking...")))

/* --- In Scala */    
object pig extends Fly with Walk{
    def fly = "Swine flu..."
    override def walk = "Pig-man walking..."
}
于 2010-12-22T14:29:17.537 回答
4

其他答案更好地说明了您问题的其他部分,但是:

它们是通过反射实现的吗?

否 - 协议编译为 JVM 接口。实现协议的东西(reify、defrecord 等)被编译为实现协议接口的 JVM 类,因此对协议函数的调用与标准 JVM 方法调用在底层是相同的。

这实际上是协议的动机之一——出于速度原因,Clojure 的许多内部数据结构都是用 Java 编写的,因为在纯 Clojure 中无法进行全速多态调度。协议提供了这一点。Clojure 的源代码中仍然包含大量 Java,但现在可以在 Clojure 中重写这些代码而不会损失性能。

于 2010-12-22T16:05:23.347 回答