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

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

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

Ответы

Ответ 1

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

  • Они выполняются во время компиляции
  • Они могут выполнять произвольное преобразование и генерировать код (используя homoiconicity кода Lisp)
  • Они подходят для "расширения языка" с помощью новых языковых конструкций или DSL.
  • Вы чувствуете себя очень сильным и можете быть очень продуктивным (в избиение средних значений)

И теперь для некоторых отличий:

Общий Lisp также позволяет макросы чтения, которые позволяют изменять поведение читателя. Это позволяет ввести совершенно новый синтаксис (например, для литералов структуры данных). Это может быть причиной того, что ваш друг описывает Clojure макросистему как "более слабую", поскольку Clojure не разрешает макросы чтения. В Clojure вы в основном придерживаетесь синтаксиса (macro-name ....), но помимо этого вы можете делать все, что хотите. Мнение делится на то, хорошо ли читатели-макросы или нет: мое личное мнение не является, поскольку оно не дает вам дополнительной "власти" и может вызвать чрезвычайную путаницу.

Clojure имеет, на мой взгляд, лучшую реализацию пространств имен, которые, по-моему, упрощают использование макросистемы Clojure. Каждый символ в Clojure является классом имен, поэтому разные библиотеки могут определять один и тот же символ, отличный от своего собственного пространства имен. Таким образом, + можно определить отдельно как clojure.core/+ and my.vector.library/+ без риска конфликтов. В вашем собственном пространстве имен вы можете use определения из другого пространства имен, что означает, что вы можете выбрать + из clojure.core > или my.vector.library по мере необходимости.

Clojure имеет дополнительные литералы для карт {} и векторов []. Это дает вам немного больше выразительности (в смысле краткого читаемого синтаксиса), чем традиционные Lisp s-выражения. В частности, использование [] для форм привязки - это соглашение в Clojure, которое, как я думаю, хорошо работает как для макросов, так и для обычного кода - это делает их четкими из других круглых скобок.

Clojure также является Lisp -1 (например, Scheme), поэтому у него нет отдельного пространства имен для функций и данных. Общий Lisp - это Lisp -2, у которого есть отдельные имена функций и данных (так что вы можете иметь как функцию foo, так и элемент данных, называемый foo). Я немного предпочитаю подход Lisp -1, так как он проще и деление между кодом и данными кажется немного произвольным, когда вы пишете в функциональном langauge. Это, вероятно, личный вкус, хотя.

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

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

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

Еще одна важная вещь, которую вы должны рассмотреть, - это "платформа", на которую вы хотите настроить таргетинг, поскольку Clojure поддерживает JVM и вместе со всеми инструментами, которые существуют для JVM platfom.

Ответ 5

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

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