Разница между Clojure Protocols и Groovy Категории - PullRequest
8 голосов
/ 30 марта 2012

Недавно увидев презентацию Clojure Protocols, я был весьма впечатлен чистым способом, которым можно сделать расширения для существующих типов таким способом. Однако я был почти уверен, что уже видел подобный способ сделать это на каком-то другом языке, и через некоторое время я обнаружил, что это Groovy Categories.

Сравните это:

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

 use (StringCategory) {
   println("TeSt".lower())
   assert "test" == "TeSt".lower()
 }

к эквиваленту протокола Clojure (взято из ответа Микеры ниже и протестировано на ideone.com )

 (defprotocol Lowerable
   (lower [x]))

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

 (println (lower "HELLO"))

мой вопрос:

  1. помимо различий в производительности (говорят, что Clojure высоко оптимизирован в этом отношении) - есть ли смысловая разница между двумя подходами?
  2. Помимо неуклюжего синтаксиса, есть ли что-то логически неправильное в подходе Groovy?

Отказ от ответственности: я новичок в Clojure!

Ответы [ 2 ]

10 голосов
/ 30 марта 2012

Вот примерный эквивалентный код Clojure с использованием протоколов:

(defprotocol Lowerable
  (lower [x]))

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

(lower "HELLO")
=> "hello"

Ключевые отличия, которые следует отметить в отношении протоколов Clojure (которые, я считаю, отличают его от версии категорий Groovy)

  • Определение протокола Clojure не содержит никакой реализации (это больше похоже на интерфейс в этом отношении).Реализация предоставляется отдельно: вы можете расширить протокол Lowerable на любое количество различных классов без необходимости вносить изменения либо в сами классы, либо в определение протокола.Например, вы можете определить lower для работы на Rope .
  • Ваша категория Groovy, указанная выше, предназначена для строк - это не относится к протоколам Clojure.В этом примере протокол Clojure «Lowerable» определен, ничего не говоря о типе аргументов.
  • lower - правильная функция первого класса.Таким образом, вы можете использовать его для построения абстракций более высокого порядка (с помощью функций более высокого порядка), которые в свою очередь будут принимать любые аргументы, на которые был расширен протокол Lowerable.
  • Протоколы Clojure сильно оптимизированы, так как они предназначены для использования быстрой отправки метода JVM.Поэтому они скомпилированы в очень эффективный код (динамическая проверка объекта или отражение не требуются)

Протоколы Clojure на самом деле являются довольно уникальным решением проблемы выражения (связанное видеодовольно интересно).Я думаю, что ближайший эквивалент протоколов Clojure на другом языке - это классы типа Haskell.Даже тогда это немного растянуло, так как Haskell типизирован статически, а Clojure динамически типизирован ....

5 голосов
/ 30 марта 2012

Функция 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

Реализации могут быть добавлены для любого типа в любое время - нет необходимости в двух написанных мною реализациях для взаимодействия каким-либо образом.

Однако я не понимаю Groovy достаточно хорошо, чтобы делать какие-либо существенные комментарии по самому вопросу;Я могу только помочь описать сторону вопроса Clojure.

...