Clojure против других Lisp [закрыто]

94

Цель моего вопроса не в том, чтобы развязать пламенную войну, а в том, чтобы определить, при каких обстоятельствах каждый язык является «лучшим инструментом для работы».

Я прочитал несколько книг по Clojure ( Programming Clojure , Practical Clojure , The Joy of Clojure и Manning Early Access edition Clojure in Action ), и я считаю, что это фантастический язык. В настоящее время я читаю Let Over Lambda, который в основном имеет дело с макросами Common Lisp, и это тоже очень интересный язык.

Я не эксперт по Лисп (скорее новичок), но это семейство языков очаровывает меня, как и функциональное программирование в целом.

Преимущества Clojure (и недостатки «других»):

  • Работает на JVM.

    • JVM - это очень стабильная, высокопроизводительная языковая среда, которая вполне соответствует мечте Sun: «Напиши один раз, запусти [почти] где угодно». Я могу написать код на своем Macbook Pro, скомпилировать его в исполняемый файл JAR, а затем запустить его в Linux и Microsoft Windows с небольшим дополнительным тестированием.

    • (Hotspot и др.) JVM поддерживает высококачественную сборку мусора и очень производительную своевременную компиляцию и оптимизацию. Если всего несколько лет назад я написал все, что должно было работать быстро, на C, теперь я без колебаний делаю это на Java.

    • Стандартная, простая, многопоточная модель. Есть ли в Common Lisp стандартный пакет многопоточности?

    • Перерывы однообразия всех этих скобок с [], {}и #{}, хотя эксперты Common Lisp, вероятно , сказать мне , что с чтением макросами, вы можете добавить их к CL.

Недостатки Clojure :

  • Работает на JVM.
    • Никакой хвостовой рекурсии или продолжений. Поддерживает ли Common Lisp продолжения? Я считаю, что схема требует поддержки обоих.

Преимущества других (в частности Common Lisp) (и недостатки Clojure):

  • Макросы считывателя, определяемые пользователем.

  • Другие преимущества?

Мысли? Другие отличия?

Ральф
источник
15
лично мне нравятся одни скобки;) похоже на "более чистый" код
Moe
3
Из того, что я прочитал в вашем списке преимуществ, я полагаю, вам также может понравиться Erlang www.erlang.org
Пер Стритцингер
4
Clojure поддерживает явную хвостовую рекурсию через специальную форму "recur". Это позволяет вам получить все преимущества хвостовой рекурсии при условии, что вы явно просите об этом (единственное исключение - то, что в настоящее время он не поддерживает взаимные хвостовые рекурсии между несколькими функциями).
mikera
1
Clojure также поддерживает продолжения, по крайней мере, в смысле «стиля передачи продолжения». Вы правы, что у него нет первоклассных продолжений. см. stackoverflow.com/questions/1173133/continuations-in-clojure
mikera
@mikera: Хвостовая рекурсия для одной функции. Две функции, вызывающие друг друга, должны выполняться с помощью "прыжков на батуте", что является своего рода путаницей (но по-своему элегантно :-)).
Ральф

Ответы:

52

Мой личный список причин, по которым я предпочитаю Clojure другим Лиспам (ps Я по-прежнему считаю, что все Лиспы великолепны!):

  • Работает на JVM - следовательно, получает автоматический доступ к фантастической инженерии в самой JVM (расширенные алгоритмы сборки мусора, оптимизация HotSpot JIT и т. Д.)

  • Очень хорошая совместимость с Java - обеспечивает совместимость с огромным набором библиотек в экосистеме языка Java / JVM. Я использовал Clojure в качестве «связующего» языка для соединения различных библиотек Java с хорошим эффектом. Поскольку я также занимаюсь разработкой большого количества Java-кода, для меня полезно, что Clojure хорошо интегрируется с инструментами Java (например, я использую Maven, Eclipse с плагином Counterclockwise для моей разработки Clojure)

  • Хороший синтаксис для векторов [1 2 3], карт {:bob 10, :jane 15}и множеств #{"a" "b" "c"}- я считаю эти инструменты довольно важными для современного программирования (конечно, помимо списков!)

  • Мне лично нравится использование квадратных скобок для привязки форм: например (defn foo [a b] (+ a b))- я думаю, что это делает код более понятным для чтения.

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

  • Отличная реализация STM для многоядерного параллелизма. Я считаю, что у Clojure лучшая история параллелизма среди всех языков на данный момент (см. Это видео, чтобы узнать больше, написанное самим Ричем Хики )

  • Это Lisp-1 (например, Scheme), который я лично предпочитаю (я думаю, что на функциональном языке имеет смысл хранить функции и данные в одном пространстве имен)

mikera
источник
2
+1 для СТМ. По сути, этого достаточно, чтобы оправдать использование Clojure.
Андре Карон
2
Вы все еще можете получить STM, используя библиотеку CL-STM.
Майк Манилоне
2
@ AndréCaron, только если вам это нужно.
правый фолд 03
Если вы хотите написать простое веб-приложение и разместить его, скажем, на дешевом хосте за 5 долларов в месяц, это, очевидно, невозможно с Clojure из-за JVM, верно?
Hexatonic
@Hexatonic Я не очень опытен, но трудно поверить, что у используемой в наши дни машины не было бы JVM.
MasterMastic
25

Имейте в виду, что Clojure - это язык и реализация (обычно на JVM). Common Lisp - это язык с более чем десятью различными реализациями. Итак, мы имеем здесь несоответствие категорий. Например, вы можете сравнить Clojure с SBCL.

В общем-то:

  • версия Common Lisp работает на JVM: ABCL

  • большинство других реализаций Common Lisp не

  • большинство реализаций CL имеют возможности многозадачности, библиотека предоставляет общий интерфейс

  • Common Lisp имеет синтаксис для массивов. Синтаксис для других типов данных может быть написан пользователем и предоставляется различными библиотеками.

  • Common Lisp не поддерживает ни оптимизацию хвостового вызова, ни продолжения. Реализации обеспечивают совокупную стоимость владения, а библиотеки обеспечивают некоторую форму продолжения.

Райнер Йосвиг
источник
24

Важное различие между Clojure и Common Lisp заключается в том, что Clojure более предписывает функциональное программирование. Философия, идиомы Clojure и, в некоторой степени, язык / библиотеки настоятельно поощряют, а иногда и настаивают на том, чтобы вы программировали функционально (без побочных эффектов, без изменяемого состояния).

Common Lisp определенно поддерживает функциональное программирование, но также допускает изменяемое состояние и императивное программирование.

Конечно, у функционального программирования есть ряд преимуществ в области параллелизма и других аспектах. Но при прочих равных хорошо иметь выбор, какой подход вы хотите использовать для каждой ситуации. Clojure не запрещает полностью императивное программирование, но он менее приспособлен к этому стилю, чем Common Lisp.

Чарли Флауэрс
источник
3
@Charlie Flowers: Я считаю, что в Common Lisp можно программировать в «чисто функциональном» стиле (поддержка постоянной структуры данных и т. Д.), Но это требует дисциплины. Верный?
Ральф
2
Просто пояснение «без побочных эффектов, без изменяемого состояния» - Clojure действительно имеет изменяемое состояние (ссылки, атомы, агенты и т. Д. Являются изменяемыми), но требует, чтобы вы осуществляли доступ к нему контролируемым способом (то есть через механизмы STM и связанные транзакционные обновление семантики)
mikera
5
@mikera: за исключением того, что Clojure полагается на использование библиотек Java для удобства использования, а все эти библиотеки требуют императивного стиля и полны побочных эффектов. Я обнаружил, что привязки с Java - это отравленный подарок ...
Андре Карон
1
@Andre - конечно, если вы решите использовать библиотеку, которая требует изменяемого состояния и императивной семантики, тогда вам нужно управлять этим. Это ничем не отличается от того, если вы обращались к такой библиотеке с любого другого языка. Но у вас есть два достойных варианта: а) не использовать такие библиотеки - вы можете написать отличный код на чистом Clojure или б) обернуть сложность взаимодействия с этими библиотеками в приятный функциональный интерфейс в стиле Clojure, с которым обычно легко работать. макросы или агенты и т. д. В целом, я обнаружил, что возможность использовать библиотеки Java гораздо больше, чем проблема.
mikera
4
@mikera: у библиотек есть преимущество. Я просто указываю, что использование библиотек Java (это одна из основных целей Rich Hickey для языка) действительно противоречит аспекту Clojure «более функциональный, чем другие шепелявые». Мой комментарий должен был означать: «если вы не переписываете / не оборачиваете эти библиотеки, вы получите императивно выглядящий код и не выиграете от более хороших частей Clojure».
Андре Карон
10

Вот хорошее видео со сравнением Scheme (в основном Racket) и Clojure .

Честно говоря, в Racket есть синтаксический сахар (дополнительный материал для чтения) для типов данных (#hash, #, квадратные скобки и т. Д.)

Кроме того, единственный способ сделать правильный хвостовой вызов Clojure - использовать recur, это обратная сторона компиляции в JVM.

Обратите внимание, что recurэто единственная конструкция цикла в Clojure, не использующая стек. Оптимизация хвостового вызова отсутствует, и использование самовызовов для зацикливания неизвестных границ не рекомендуется. recurявляется функциональным, и его использование в хвостовой позиции проверяется компилятором. ( Особые формы ).

Даниил
источник
Линк мертв, я думаю.
nawfal
1
@nawfal Кажется, я исправил
Даниил
6
Ссылка мертва (снова?)
Выкинь аккаунт
1
Похоже, видео по этой ссылке можно найти здесь: vimeo.com/22675078 .
GDP2
Есть также trampolineдля хвостовых криков.
HappyFace