Clojure Protocols против Scala Структурные Типы

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

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

4 ответа

Решение

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

Скала - статически типизированный язык. 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, и получить правильную идентификацию объекта также сложно.

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

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

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

Как я понял из этого вступительного поста в блоге, протоколы закрытия ближе к чертам 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..."
}

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

Они реализованы через отражения?

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

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

Другие вопросы по тегам