Они оба в значительной степени эквивалентны с точки зрения того, что вы можете с ними сделать, то есть:
- Они выполняются во время компиляции
- Они могут выполнять произвольное преобразование и генерацию кода (используя гомоконичность кода Lisp)
- Они подходят для "расширения языка" с помощью новых языковых конструкций или DSL
- Вы чувствуете себя очень могущественным и можете быть очень продуктивным (при избиении средних значений )
А теперь о некоторых различиях:
Common Lisp также позволяет макросам чтения , которые позволяют вам изменить поведение читателя. Это позволяет вводить совершенно новый синтаксис (например, для литералов структуры данных). Это может быть причиной того, что ваш друг описывает макрос-систему Clojure как «более слабую», поскольку Clojure не допускает макросы читателя. В Clojure вы в основном застряли с синтаксисом (macro-name ....)
, но помимо этого вы можете делать все, что захотите. Мнения разделились относительно того, хорош ли читательский макрос, или нет: мой личный взгляд - нет, так как он не дает вам никакой дополнительной «силы» и потенциально может вызвать крайнюю путаницу.
Clojure, на мой взгляд, имеет более приятную реализацию пространств имен , что, на мой взгляд, облегчает использование макрос-системы Clojure. Каждый символ в Clojure квалифицирован для пространства имен, поэтому разные библиотеки могут определять один и тот же символ в своем пространстве имен. Таким образом, +
может быть определен отдельно как clojure.core/+
and my.vector.library/+
без риска возникновения конфликтов. В своем собственном пространстве имен вы можете использовать определений из другого пространства имен, что будет означать, что вы можете выбрать +
из clojure.core
или my.vector.library
по мере необходимости.
С другой стороны, Clojure имеет дополнительные литералы для карт {}
и векторы []
. Они дают вам немного больше выразительности (в смысле краткого читаемого синтаксиса), чем традиционные s-выражения Lisp. В частности, использование [] для связывания форм - это соглашение в Clojure, которое, на мой взгляд, хорошо работает как для макросов, так и для нормального кода - оно четко выделяет их из других скобок.
Clojure также является Lisp-1 (как Scheme), поэтому у него нет отдельного пространства имен для функций и данных. Common Lisp - это Lisp-2 , который имеет отдельные функции и пространства имен данных (поэтому вы можете иметь как функцию с именем foo, так и элемент данных с именем foo). Я немного предпочитаю подход Lisp-1, так как он проще, и разделение между кодом и данными кажется немного произвольным, когда вы пишете в функциональном языке. Это, вероятно, вещь личного вкуса.
В целом, различия относительно незначительны. Я думаю, что Clojure немного проще и элегантнее, тогда как Common Lisp имеет некоторые дополнительные функции (используйте на свой страх и риск!). Оба очень способные, поэтому вы не ошибетесь, выбрав любой из них.