首页 文章

Clojure协议与Scala结构类型

提问于
浏览
10

在Clojure 1.2中观看了Protocols,并且对Clojure知之甚少之后,我对Clojure Protocols有一些疑问:

  • 他们是否打算在Scala中执行与Structural Types相同的操作?协议对结构类型(性能,灵活性,代码清晰度等)有什么好处?它们是通过反思实现的吗?

  • 与Scala的互操作性问题:可以使用协议代替Scala中的结构类型吗?它们可以在Scala中扩展(如果'extension'术语可以应用于协议)吗?

4 回答

  • 10

    完全不相关 .

    Scala是一种静态类型语言 . Clojure是一种动态类型语言 . 这种差异从根本上影响了它们 .

    结构类型是静态类型,周期 . 它们只是让编译器静态证明一个对象具有特定结构的一种方式(我说在这里证明,但是铸造可能会像往常一样导致虚假证明) .

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

    与Java接口一样,Scala特性更接近协议,但同样存在静态与动态问题 . Scala特征必须在编译时与类关联,类似于Java接口 . 在事实之后,甚至可以由第三方将Clojure协议添加到数据类型中 .

    像Java和Scala这样的Clojure协议可以通过包装器/代理模式或动态代理(http://download.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html)等机制实现 . 但是这些将比Clojure协议更加笨拙,并且获得对象身份也很棘手 .

  • 4

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

    [见:Simple explanation of clojure protocols.]

    Scala对表达式问题的解决方案是隐含的 . 因此,从语义上讲,这是与Scala中Clojure协议最接近的等价物 . (在Haskell中,它将是Typeclasses或类型系列 . )

  • 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..."
    }
    
  • 15

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

    他们是通过反思实施的吗?

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

    这实际上是协议的激励因素之一 - 由于速度原因,很多Clojure的内部数据结构都是用Java编写的,因为在纯Clojure中无法进行全速多态分派 . 协议提供了这一点 . Clojure的源代码中仍然有很多Java,但现在可以在Clojure中重写所有内容而不会损失性能 .

相关问题