Как далеко могут идти макросы LISP? [закрыто]

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

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

5.08.2008 07:32:54
Схемы макросов очень мощные. Я написал полную реализацию LINQ как макрос Scheme некоторое время назад. https://ironscheme.svn.codeplex.com/svn/IronScheme/IronSchemeConsole/ironscheme/linq.ss Со всей этой мощью у меня заканчиваются хорошие идеи для ее применения!
leppie 17.09.2008 12:20:10
Özgür 8.03.2009 00:32:46
Обратите внимание, что lisp является объектно-ориентированным. Смотрите Common Lisp Object System.
catphive 4.11.2011 18:28:49
Существуют макросы, которые позволяют кодировать непосредственно на C в Lisp, но код C может проходить через мощный язык Lisp, и макросы произвольно запускают код во время компиляции, а не во время выполнения.
aoeu256 22.07.2019 12:03:26
14 ОТВЕТОВ
РЕШЕНИЕ

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

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

Макросы не застряли в 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)))

Смотрите эту страницу, чтобы узнать, как это сделать.

35
15.09.2008 15:07:21
Ваш пример макроса "не застрял в s-выражениях" выглядит для меня как s-выражение.
Hugh Allen 29.09.2008 13:06:54
Примером макроса цикла является s-expr, но «подвыражения» - нет.
Eric Normand 8.10.2008 15:41:20
Это действительно хороший вопрос. Но не для stackoverflow.com; это не задача или что-то, на что можно ответить однозначно, без учета мнения и религии, чтобы заполнить пустоты, где анализ уходит в неопределенные временные промежутки.
Kaz 22.03.2012 05:25:13
@ Каз, но почему-то этого не произошло, и ответы тоже великолепны :)
Luka Ramishvili 1.08.2012 05:49:02

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

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

2
5.08.2008 07:40:26

@sparkes

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

1
5.08.2008 07:45:14

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

1
6.08.2008 12:14:12
«кроме открытия и закрытия парен» <- Вы даже можете изменить это. См. Planet.plt-scheme.org/package-source/chongkai/sml.plt/1/6/… для получения информации о стандартном ML, встроенном в схему (ракетку) с использованием макроса, эквивалентного макросу читателя схемы.
p4bl0 7.01.2011 00:13:48

Обычные макросы работают со списками объектов. Чаще всего этими объектами являются другие списки (образующие деревья) и символы, но это могут быть и другие объекты, такие как строки, хеш-таблицы, пользовательские объекты и т. Д. Эти структуры называются s-exps .

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

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

Вы немного озадачены, когда упоминаете «функциональную природу» Лиспа и «объектно-ориентированный синтаксис» Руби. Я не уверен, каким должен быть «объектно-ориентированный синтаксис», но Lisp - это мультипарадигмальный язык, и он очень хорошо поддерживает объектно-ориентированное программирование .

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

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

11
26.08.2008 14:02:24

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

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

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

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

16
26.08.2008 09:49:02

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

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

6
15.09.2008 12:07:06

Скобка ад? Я не вижу больше скобок в:

(function toto)

чем в:

function(toto);

И в

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

не более чем в:

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

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

11
20.02.2009 11:11:23
Посмотрите на некоторый синтаксис Ruby ... вы можете полностью отбросить парены, если только они не АБСОЛЮТНО необходимы для устранения двусмысленности ... даже Haskell, который также сильно функционален, не привязан к паренсу, подобному Lisp (или другим языкам, как вы указали)
Mike Stone 17.09.2008 17:37:01
@ Майк: ты прав. Но Lisp против C / C ++ / Java / C #: у него не так много скобок, гораздо меньше скобок и нет полуколонок! И это было 50 лет назад, это всегда поражало меня.
Sébastien RoccaSerra 19.09.2008 21:20:16
можно написать читатель в / для lisp, который использует отступы и не нуждается в скобках. это было бы о странице кода. это сильно изменится? это все равно что искать жену за ее внешность ... хотя, как бы глупо это ни было, многие так делают ... :)
Attila Lendvai 14.03.2009 23:14:10
Аттила, всякий раз, когда я вижу код Python, я задаюсь вопросом, можно ли написать программу чтения, которая не нуждается в конкретном пробеле и использует вместо этого круглые скобки.
Svante 20.03.2009 23:34:32

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

Common Lisp имеет встроенную возможность определять новый синтаксис для макросов ридера и ридера для обработки этого синтаксиса. Эта обработка выполняется во время чтения (предшествующего времени компиляции или оценки). Чтобы узнать больше об определении макросов читателя в Common Lisp, см. Hyperpec Common Lisp - вам нужно прочитать Ch. 2 «Синтаксис» и гл. 23, «Читатель» . (Я полагаю, что у Scheme такая же возможность, но я не настолько знаком с ней - см. Источники Scheme для языка программирования Arc ).

В качестве простого примера, давайте предположим, что вы хотите, чтобы 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 #\( #\[ )

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

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

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

24
16.09.2008 19:36:43

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

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

Удачи!

15
16.09.2008 19:29:54
Что ж, я признаю, что никогда не использовал Lisp или диалект в течение длительного времени, но мне вполне удобно использовать синтаксис (и его простота довольно удивительна), но я все же предпочитаю синтаксис Ruby перед любым другим языком, который я использовал.
Mike Stone 17.09.2008 17:34:42
Что, если синтаксис может быть чем-то, что вы считаете подходящим для выражения программы под рукой?
jfm3 18.09.2008 20:08:57
На самом деле, кто-то разработал серьезный синтаксис программирования общего назначения поверх S-выражений - "Sweet-выражения" . Они сохраняют все преимущества гибкости S-выражений. Знакомые с Lisp пользователи этого расширения не предпочитают "адские скобки". Однако Sweet-выражения не завоевали популярность. Я предполагаю, что это потому, что автор Sweet-выражений реализовал этот синтаксис только для нескольких диалектов Lisp и написал небольшую документацию по установке этих расширений.
Rory O'Kane 18.03.2012 06:18:54

Посмотрите на этот пример того, как макросы читателя могут расширить читатель 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/

2
17.09.2008 00:30:43

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

9
17.09.2008 12:14:53

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

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

1
19.09.2008 10:43:32

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

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

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

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

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

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

13
8.03.2014 08:39:32