Clojure协议和Groovy类别之间的区别

Ice*_*e09 8 groovy protocols clojure categories

最近看过Clojure Protocols的演示文稿,我对现有类型的简洁方式扩展印象非常深刻.但是,我很确定已经在其他语言中看到了类似的方法,经过一段时间我发现它是Groovy Categories.

比较一下:

 @Category(String) ?class StringCategory {
   String lower() {
     return this.toLowerCase()
   }
 }

 use (StringCategory) {
   println("TeSt".lower())
   assert "test" == "TeSt".lower()
 }
Run Code Online (Sandbox Code Playgroud)

与Clojure协议相当(取自下面的迈克拉答案并在ideone.com中测试)

 (defprotocol Lowerable
   (lower [x]))

 (extend-protocol Lowerable
   String
     (lower [s] 
       (.toLowerCase s)))

 (println (lower "HELLO"))
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 除了性能差异(据说Clojure在这方面得到高度优化) - 这两种方法之间是否存在语义差异?
  2. 除了笨拙的语法之外,Groovy方法还有什么逻辑上的错误吗?

免责声明:我是一个完整的Clojure新手!

mik*_*era 10

这是使用协议的粗略等效Clojure代码:

(defprotocol Lowerable
  (lower [x]))

(extend-protocol Lowerable
  String
    (lower [s] 
      (.toLowerCase s)))

(lower "HELLO")
=> "hello"
Run Code Online (Sandbox Code Playgroud)

关于Clojure协议的关键区别(我认为它与Groovy类别版本不同)

  • Clojure协议定义不包含任何实现(在这方面它更像是一个接口).实现是单独提供的:您可以将Lowerable协议扩展到任意多个不同的类,而无需对类本身或协议定义进行任何更改.例如,您可以定义lower为在绳索上工作.
  • 上面的Groovy类别专门用于字符串 - 这与Clojure协议不同.在这个例子中,定义了Clojure协议"Lowerable",但没有说明任何关于参数类型的内容.
  • lower是一个适当的一流功能.因此,您可以使用它来构建更高阶的抽象(通过更高阶函数),这反过来将接受可扩展协议已被扩展的任何参数.
  • Clojure协议经过了大量优化,因为它们旨在利用JVM的快速方法分派.因此,它们被编译成非常有效的代码(不需要动态对象检查或反射)

Clojure协议实际上是表达式问题的一种相当独特的解决方案(链接视频非常有趣).我认为在另一种语言中与Clojure协议最接近的等价物实际上是Haskell类型.即便如此,由于Haskell是静态类型的,并且Clojure是动态类型的,所以它有点延伸....


ama*_*loy 5

他所指的Clojure功能如下:

(defprotocol StringMunging
  (lower [this]))

(extend-protocol StringMunging
  String
  (lower [this]
    (.toLowerCase this))

  clojure.lang.Keyword
  (lower [this]
    (keyword (lower (name this)))))

user> (lower "TeSt")
"test"
user> (lower :TeSt)
:test
Run Code Online (Sandbox Code Playgroud)

可以随时为任何类型添加实现 - 我写的两个实现都不需要以任何方式进行协作.

但是,我不太了解Groovy对这个问题本身做出任何实质性的评论; 我只能帮助描述问题的Clojure方面.