Clojure Протоколы vs Scala Структурные типы

После просмотра интервью с Rich Hickey на Protocols in Clojure 1.2, и очень мало знает о Clojure, у меня есть некоторые вопросы о Clojure Protocols:

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

Ответ 1

Полностью не связан.

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, и получение прав на объекты тоже сложно.

Ответ 2

Цель протоколов в Clojure заключается в эффективном решении проблемы с выражением.

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

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

Ответ 3

Как я понял из этого вводного blogpost, Closure Protocols ближе к 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

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

Выполняются ли они через отражения?

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

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