Clojure Protocols против Scala Структурные Типы - PullRequest
10 голосов
/ 22 декабря 2010

После просмотра интервью с Ричем Хики на Протоколах в Clojure 1.2 и очень мало зная о Clojure, у меня есть несколько вопросов по протоколам Clojure:

  • Они предназначены для того же, что и Структурные типы в Scala? Какие преимущества имеют протоколы по сравнению со структурными типами (производительность, гибкость, четкость кода и т. Д.)? Они реализованы через отражения?
  • Вопросы по взаимодействию со Scala: можно ли использовать протоколы вместо структурных типов в Scala? Можно ли их продлить (если термин «продление» можно применить к протоколам) в Scala?

Ответы [ 4 ]

15 голосов
/ 22 декабря 2010

Совершенно не связано.

Scala - статически типизированный язык. Clojure - это динамически типизированный язык. Это различие фундаментально формирует их обоих.

Структурные типы - это статические типы, точка. Это просто способ заставить статически доказать компилятору, что объект будет иметь определенную структуру (я говорю «докажи здесь», но приведение может вызвать ложные доказательства, как всегда).

Протоколы в Clojure - это способ создания динамической отправки, которая намного быстрее, чем отражение или поиск объектов на карте. В семантическом смысле они на самом деле не расширяют возможности Clojure, но в оперативном отношении они значительно быстрее, чем механизмы, которые использовались ранее.

Черты Scala немного ближе к протоколам, как и интерфейсы Java, но, опять же, существует проблема статики и динамики. Черты Scala должны быть связаны с классом во время компиляции, подобно интерфейсам Java. Протоколы Clojure могут быть добавлены к типу данных во время выполнения даже после того, как это произошло третьей стороной.

Нечто подобное протоколам Clojure возможно в Java и Scala с помощью таких механизмов, как шаблоны оболочки / прокси или динамические прокси (http://download.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html). Но они будут чертовски неуклюжими по сравнению с протоколами Clojure, и получить правильную идентификацию объекта также сложно.

10 голосов
/ 22 декабря 2010

Цель протоколов в Clojure - эффективно решить проблему выражения.

[См .: Простое объяснение протоколов clojure . ]

Решение Scala для проблемы выражений - это последствия.Итак, семантически, , что является наиболее близким эквивалентом Clojure Protocols в Scala.(В Haskell это будут классы типов или семейства типов.)

6 голосов
/ 22 декабря 2010

Как я понял из этого вступительного блога , протоколы закрытия ближе к чертам Scala, а не к структурным типам (и, следовательно, не могут быть использованы вместо них, отвечая на мой второй вопрос):

/* ----------------------- */
/* --- 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..."
}
4 голосов
/ 22 декабря 2010

Другие ответы лучше говорят на другие части вашего вопроса, но:

Реализуются ли они через отражения?

Нет - протоколы компилируются в интерфейсы JVM. Вещи, которые реализуют протоколы (reify, defrecord и т. Д.), Компилируются в классы JVM, которые реализуют интерфейс протокола, поэтому вызовы функций протокола такие же, как вызовы стандартных методов JVM, под капотом.

Это был фактически один из мотиваторов для протоколов - многие внутренние структуры данных Clojure были написаны на Java по соображениям скорости, потому что в чистом Clojure не было способа осуществить полиморфную диспетчеризацию с полной скоростью. Протоколы обеспечивают это. Clojure по-прежнему имеет много Java в своем исходном коде, но теперь все это можно переписать в Clojure без потери производительности.

...