Протоколы Clojure против структурных типов Scala
-
12-10-2019 - |
Вопрос
После просмотра Интервью с Рич Хикки на Протоколы В Clojure 1.2, и очень мало зная о Clojure, у меня есть несколько вопросов по протоколам Clojure:
- Они предназначены для того, чтобы сделать то же самое, что и Структурные типы в Скале? Какие преимущества имеют протоколы над структурными типами (производительность, гибкость, ясность кода и т. Д.)? Они реализованы через размышления?
- Вопросы о совместимости со Scala: можно ли использовать протоколы вместо структурных типов в Scala? Могут ли они быть расширены (если можно применить к «расширению» термины к протоколам) в 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, и правильно, что идентификация объекта также сложно.
Другие советы
Целью протоколов в Clojure является эффективное решение проблемы выражения.
Видеть: Простое объяснение протоколов Clojure.]
Решение Скалы в отношении проблемы выражения является последствием. Итак, семантически, что является наиболее близким эквивалентом протоколов Clojure в 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 все еще есть много Java в своем исходном коде, но теперь все это может быть переписано в Clojure без потери производительности.