Макросы, clojure vs common lisp - PullRequest
       17

Макросы, clojure vs common lisp

16 голосов
/ 08 марта 2012

Несколько моих друзей и я работаем над новой платформой, и мы хотим встроить ее в lisp. Главной достопримечательностью являются макросы. Мы все используем Common Lisp, но я хочу изучить возможность Clojure.

Когда я предложил это, один из них сказал, что макросистема «слабее». Я хотел знать, правда ли это, и в каких областях.

Ответы [ 5 ]

25 голосов
/ 08 марта 2012

Они оба в значительной степени эквивалентны с точки зрения того, что вы можете с ними сделать, то есть:

  • Они выполняются во время компиляции
  • Они могут выполнять произвольное преобразование и генерацию кода (используя гомоконичность кода 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 имеет некоторые дополнительные функции (используйте на свой страх и риск!). Оба очень способные, поэтому вы не ошибетесь, выбрав любой из них.

12 голосов
/ 14 апреля 2012

Что касается обычных макросов, то здесь есть различия между вариантами Lisp и Clojure:

  1. Clojure Lisp-1 , а CL Lisp-2 . История показала, что макросы в языке с одним пространством имен обычно более подвержены ошибкам, потому что существует большая вероятность конфликта имен. Чтобы решить эту проблему, Clojure использует нетрадиционную реализацию квази-кавычек.
  2. Но это обходится дорого: поскольку в Clojure символы внутри обратной цитаты охотно решаются в пространстве имен, где определяются макросы, существует множество тонких проблем, таких как этот .
  3. Макросы Clojure используют автогензимы. Это объявлено как преимущество, и оно действительно удаляет некоторые шаблоны (конечно, вы можете достичь того же в Lisp - см. defmacro! ). И концептуальный вопрос о том, когда использовать генсимы, очевидно, остается.

Итак, в целом подход Лиспа более грубый, но более гибкий. Макросы Clojure могут быть немного легче доступны, но их становится сложнее использовать, когда вы выходите за рамки простых модификаций синтаксиса и начинаете определять полные DSL.

Относительно макросов читателя , как вы знаете, Clojure не предоставляет эту опцию пользователю, в то время как CL делает. Таким образом, в макросах для чтения CL можно найти множество применений, таких как интерполяция строк , поддержка интернационализации , SQL DSL или взаимодействие Java . Не говоря уже о множестве особых случаев, когда можно использовать макросы считывателя для создания расширенных DSL.

4 голосов
/ 22 марта 2012

Я был программистом LISP на машинах LISP в 80-х. С точки зрения производительности, я все еще должен увидеть сопоставимую среду разработки. Тем не менее, макросистема clojure достаточно мощна, чтобы ею уже злоупотреблять. Макросы помогают, когда вам нужно реализовать «компилятор» нового языка, и вы сможете описать его в формальной нотации. Не потому, что это абсолютно необходимо для вас. Это нужно пользователям самого нового языка. Таким образом, это должен быть очень полезный формальный язык, чтобы заслужить компилятор и формальную запись. Если это не так, держитесь подальше от макросов и используйте чисто функциональный стиль программирования для создания абстракций. Вы снова почувствуете радость последовательного кодирования с вашим аналогом, вместо того, чтобы быть ближе к тупым последовательностям битов. И пользователи вашего кода тоже будут счастливее. Я надеюсь, что неправильное использование макросов не будет следующей случайной сложностью. Старый новичок Лиспера и Клочюра.

1 голос
/ 09 марта 2012

Макросы Clojure имеют ряд преимуществ:

  • случайный захват символов затруднен, поскольку пространство имен расширяет символы
  • макросы читателей других народов вас не укусят (не ваш или конечно, я говорю об этом другом;))
  • autogensyms берет много беспорядка из написания гигиенических макросов.
1 голос
/ 08 марта 2012

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

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

...