Подтвердить что ты не робот

Как далеко могут пройти макросы LISP?

Я много читал, что LISP может переопределить синтаксис "на лету", предположительно с помощью макросов. Мне любопытно, как далеко это происходит? Можете ли вы переопределить структуру языка настолько, что она граничит с компилятором для другого языка? Например, можете ли вы изменить функциональный характер LISP на более объектно-ориентированный синтаксис и семантику, возможно, сказать, что синтаксис ближе к чему-то вроде Ruby?

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

4b9b3361

Ответ 1

Это действительно хороший вопрос.

Я думаю, что он нюансирован, но определенно подотчетен:

Макросы не застревают в s-выражениях. См. Макрос LOOP для очень сложного языка, написанного с использованием ключевых слов (символов). Итак, хотя вы можете начинать и заканчивать цикл круглыми скобками, внутри он имеет свой собственный синтаксис.

Пример:

(loop for x from 0 below 100
      when (even x)
      collect x)

При этом большинство простых макросов просто используют s-выражения. И вы будете "застревать", используя их.

Но s-выражения, как ответил Серджио, начинают чувствовать себя правильно. Синтаксис убирается с пути, и вы начинаете кодирование в дереве синтаксиса.

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

#R{
      ruby.code.goes.here
  }

Но вам нужно написать собственный синтаксический анализатор синтаксиса Ruby.

Вы также можете имитировать некоторые из конструкций Ruby, например блоков, с макросами, которые скомпилируются с существующими конструкциями Lisp.

#B(some lisp (code goes here))

переводится на

(lambda () (some lisp (code goes here)))

Подробнее о том, как это сделать, см. эту страницу.

Ответ 2

Да, вы можете переопределить синтаксис, чтобы Lisp стал компилятором. Вы делаете это с помощью "Макросов чтения", которые отличаются от обычных "Макросов компилятора", о которых вы, вероятно, думаете.

Common Lisp имеет встроенное средство для определения нового синтаксиса для чтения и чтения макросов для обработки этого синтаксиса. Эта обработка выполняется во время чтения (которое происходит до компиляции или времени вычисления). Чтобы узнать больше об определении макросов читателя в Common Lisp, см. Common Lisp Hyperspec - вы захотите прочитать Ch. 2, "Синтаксис" и Ch. 23, "Читатель" . (Я считаю, что схема имеет тот же объект, но я не так хорошо знаком с ним - см. Источники схемы для Язык программирования дуги).

В качестве простого примера предположим, что вы хотите, чтобы Lisp использовал фигурные скобки, а не круглые скобки. Для этого требуются следующие определения читателей:

;; { and } become list delimiters, along with ( and ).
(set-syntax-from-char #\{ #\( )
(defun lcurly-brace-reader (stream inchar) ; this was way too easy to do.
  (declare (ignore inchar))
  (read-delimited-list #\} stream t))
(set-macro-character #\{ #'lcurly-brace-reader)

(set-macro-character #\} (get-macro-character #\) ))
(set-syntax-from-char #\} #\) )

;; un-lisp -- make parens meaningless
(set-syntax-from-char #\) #\] ) ; ( and ) become normal braces
(set-syntax-from-char #\( #\[ )

Вы говорите Lisp, что {похож на (и тот) как a). Затем вы создаете функцию (lcurly-brace-reader), которую читатель будет вызывать всякий раз, когда видит {, и вы используете set-macro-character для назначения этой функции {. Затем вы указываете Lisp, что (и) похожи на [и] (то есть не значимый синтаксис).

Другие вещи, которые вы могли бы сделать, включают в себя, например, создание нового синтаксиса строк или использование [и], чтобы заключить в себя нотацию и процесс исправления это в S-выражения.

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

Ответ 3

Я не эксперт Lisp, черт возьми, я даже не программист Lisp, но после небольшого эксперимента с языком я пришел к выводу, что через некоторое время скобки начинают становиться "невидимыми", и вы начинаете видеть код так, как хотите. Вы больше обращаете внимание на синтаксические конструкции, которые вы создаете с помощью s-exprs и макросов, и меньше на лексическую форму текста списков и скобок.

Это особенно актуально, если вы воспользуетесь хорошим редактором, который помогает с окраской отступов и синтаксиса (попробуйте установить скобки в цвет, очень похожий на фон).

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

Я знаю, что это просто эмпирическое наблюдение, но я думаю, что у меня был один из тех Lisp моментов просветления, когда я это понял.

Ответ 4

Снова и снова новички в Lisp хотят "избавиться от всех скобок". Это длится несколько недель. Ни один проект для создания серьезного синтаксиса программирования общего назначения поверх обычного синтаксического анализатора S-expression никогда не получает нигде, потому что программисты неизменно предпочитают то, что вы в настоящее время воспринимаете как "скобки в конце". Это немного привыкает, но не так много! Как только вы привыкнете к этому, и вы действительно сможете оценить пластичность синтаксиса по умолчанию, возвращаясь к языкам, на которых действительно существует только один способ выразить какую-либо конкретную конструкцию программирования.

При этом Lisp является отличным субстратом для создания доменных языков. Так же хорошо, как если бы не лучше, чем XML.

Удачи!

Ответ 5

Лучшее объяснение макросов Lisp, которые я когда-либо видел, находится на

https://www.youtube.com/watch?v=4NO83wZVT0A

начинающийся примерно через 55 минут. Это видео-беседа, написанная Питером Сейбелом, автором "Практического общего Lisp", который является лучшим учебником Lisp.

Мотивация макросов Lisp, как правило, трудно объяснить, потому что они действительно приходят в свои права в ситуациях, которые слишком велики для представления в простом учебнике. Питер придумал отличный пример; вы можете полностью понять его, и это делает хорошее, правильное использование макросов Lisp.

Вы спросили: "Не могли бы вы изменить функциональный характер Lisp на более объектно-ориентированный синтаксис и семантику". Ответ - да. Фактически, Lisp изначально не имел никакого объектно-ориентированного программирования вообще, неудивительно, так как Lisp был вокруг со времен перед объектно-ориентированным программированием! Но когда мы впервые узнали об ООП в 1978 году, мы смогли легко добавить его в Lisp, используя, помимо прочего, макросы. В итоге была разработана Common Lisp Object System (CLOS) - очень мощная объектно-ориентированная система программирования, которая элегантно вписывается в Lisp. Все это можно загрузить как расширение - ничего не встроено! Все это делается с помощью макросов.

Lisp имеет совершенно другую функцию, называемую "макросами читателя", которая может использоваться для расширения поверхностного синтаксиса языка. Используя макросы чтения, вы можете создавать подъязыки с синтаксисом типа C или Ruby. Они преобразуют текст в Lisp, внутренне. Они не используются широко большинством реальных программистов Lisp, главным образом потому, что трудно расширить интерактивную среду разработки, чтобы понять новый синтаксис. Например, команды отступа Emacs будут смущены новым синтаксисом. Если вы энергичный, Emacs также расширяется, и вы можете научить его новому лексическому синтаксису.

Ответ 6

Регулярные макросы работают с списками объектов. Чаще всего эти объекты представляют собой другие списки (таким образом формируя деревья) и символы, но они могут быть другими объектами, такими как строки, хеш-таблицы, пользовательские объекты и т.д. Эти структуры называются S-EXPS.

Итак, когда вы загружаете исходный файл, ваш компилятор Lisp будет анализировать текст и производить s-exp. На них работают макросы. Это прекрасно работает, и это чудесный способ расширить язык в духе s-exps.

Кроме того, вышеупомянутый процесс синтаксического анализа может быть расширен через "макросы читателя", которые позволяют настроить способ преобразования текста в s-exps. Однако я предлагаю вам вместо синтаксиса Lisp вместо сгибать его во что-то другое.

Звучит немного смутно, когда упоминается Lisp "функциональный характер" и "объектно-ориентированный синтаксис Ruby". Я не уверен, что должен быть "объектно-ориентированный синтаксис", но Lisp - это язык с несколькими парадигмами и он отлично поддерживает объектно-ориентированное программирование.

Кстати, когда я говорю Lisp, я имею в виду Common Lisp.

Я предлагаю вам отложить свои предрассудки и дать Lisp честный ход.

Ответ 7

Скорбный ад? Я больше не вижу круглых скобок:

(function toto)

чем в:

function(toto);

И в

(if tata (toto)
  (titi)
  (tutu))

не более:

if (tata)
  toto();
else
{
  titi();
  tutu();
}

Я вижу меньше скобок и ';' хотя.

Ответ 8

То, что вы просите, несколько напоминает вопрос о том, как стать экспертом-шоколадом, чтобы вы могли удалить все эти адские коричневые вещи из своего любимого шоколадного торта.

Ответ 9

Да, вы можете принципиально изменить синтаксис и даже избежать "скобок в скобках". Для этого вам нужно будет определить новый синтаксис читателя. Посмотрите на макросы читателей.

Я подозреваю, однако, что для достижения уровня Lisp опыта для программирования таких макросов вам нужно будет погрузиться в язык настолько, что вы больше не будете рассматривать parenthese "ад". То есть к тому времени, как вы знаете, как их избежать, вы придете принять их как хорошее.

Ответ 10

Если вы хотите, чтобы lisp выглядел как Ruby, используйте Ruby.

Возможно использование Ruby (и Python) очень похоже на lisp, что является одной из основных причин, по которым они получили признание так быстро.

Ответ 11

@sparkes

Иногда LISP - это чистый выбор языка, а именно расширения Emacs. Я уверен, что я мог бы использовать Ruby для расширения Emacs, если бы захотел, но Emacs был разработан для расширения с помощью LISP, поэтому, похоже, имеет смысл использовать его в этой ситуации.

Ответ 12

см. этот пример того, как макросы читателя могут расширить читатель lisp с помощью сложных задач, таких как XML-шаблоны:

http://common-lisp.net/project/cl-quasi-quote/present-class.html

эта пользовательская библиотека компилирует статические части XML в кодированные в UTF-8 литеральные массивы байтов во время компиляции, которые готовы к последовательности записи в сетевой поток. и они применимы в обычных макросах lisp, они ортогональны... размещение символа запятой влияет на то, какие части являются постоянными и которые должны оцениваться во время выполнения.

более подробная информация доступна по адресу: http://common-lisp.net/project/cl-quasi-quote/

другой проект, который для Common lisp расширений синтаксиса: http://common-lisp.net/project/cl-syntax-sugar/

Ответ 13

Это сложный вопрос. Поскольку lisp уже структурно настолько близко к дереву синтаксического разбора, разница между большим количеством макросов и реализацией собственного мини-языка в генераторе парсера не очень ясна. Но, за исключением открытого и закрывающего paren, вы могли бы легко получить что-то, что не похоже на lisp.

Ответ 14

Одно из применений макросов, которые взорвали мой мозг, - это проверка времени выполнения запросов SQL от DB.

Как только вы поймете, что у вас есть полный язык под рукой во время компиляции, он открывает интересные новые перспективы. Это также означает, что вы можете стрелять себе в ногу по-новому (например, рендеринг компиляции, не воспроизводимый, что очень легко превратить в кошмар отладки).