LINUX.ORG.RU

Синтаксис и LISP'ы

 , ,


0

1

Часто можно наткнуться на мнение, что у лиспа(ов) нет синтаксиса. Хотелось бы понять, что конкретно тут имеется в виду.

Во-первых, синтаксическая запись s-expr'ов так же является некоторым языком, со своими синтаксическими правилами и возможностью описания посредством грамматики.

Во-вторых, различные диалекты лиспа вводят специальные дополнительные синтаксические конструкции, вроде [ и ] в clojure или typed racket.

Имеется в виду, что этот синтаксис прост и фактически без особых изменений определяет AST?


Ответ на: комментарий от anonymous

Там в этом и заключается спор. В лиспе примитивный синтаксис - фактически, ручная запись AST в чистом виде. За некоторыми оговорками. Все остальное - уже семантика. Семантика у лиспа есть и может быть изменена макросами.

anonymous
()
Ответ на: комментарий от elyadow

В схемах есть syntax objects, в которые твой код и парсится. И они ничего общего с твоими списками и символами не имеют. Там кроме распарсенной скобкоты еще и куча метаданных (положение в исходном файле, путь к самому файлу, еще всякая хрень).

anonymous
()
Ответ на: комментарий от anonymous

Да не, там все равно при выполнении идет синтаксический разбор. Разные выражения — функция, аппликация, присваивание и т.д.

anonymous
()
Ответ на: комментарий от antares0

С точки зрения лиспа здесь список и атомы и функциональный вызов.

С точки зрения лиспа здесь вызов макроса, который вернёт корректный AST.

Тело макроса имеет (как правило) синтаксис. Здесь loop имеет синтаксис.

Если же попыться выделить синтаксис именно Loop-а то затык будет в конечности элементов Loop-овско DSL

А можно пример языка с бесконечным количеством элементов?

Так для примера будет довольно сложно написать синтаксический корректный, но неверный семантически пример.

(loop for i from 1 to 10 do (incf i -1))

Или если я тебя не так понял, то приведи такой пример для for(...;...;...) {...}

monk ★★★★★
()
Ответ на: комментарий от elyadow

парсится так же, как, например, (+ x y z 1 a 10 b c),

А ещё в Common lisp бывает #D{x+y*z}, который парсится внезапно совсем по-другому.

monk ★★★★★
()
Ответ на: комментарий от monk

Тело макроса имеет (как правило) синтаксис. Здесь loop имеет синтаксис.

Макрос берет AST и делает AST. Это уже этап семантического анализа. Синтаксический анализ берет текст и по правилам грамматики формирует из него AST. Макросы этого не делают. Даже loop.

anonymous
()
Ответ на: комментарий от monk

С точки зрения лиспа здесь вызов макроса

Не-а. При построении АСТа никто еще не знает, что loop - это макрос.

anonymous
()
Ответ на: комментарий от monk

Ну это ридер макросы. Ридер-макросы меняют синтаксис, все верно. Обычные макросы - не меняют.

anonymous
()
Ответ на: комментарий от elyadow

В Лиспе список из символов и чисел, а в другом языке АСТ для цикла.

На том уровне, где в лиспе список символов и чисел, в другом языке список токенов. А уж чем формируется АСТ для цикла — макросом или компилятором — дело десятое.

Синтаксис в лиспе не отсутствующий, а перенастраиваемый.

Это тоже Common Lisp:

define factorial(n)
  if {n <= 1}
    1
    {n * factorial{n - 1}}

monk ★★★★★
()
Ответ на: комментарий от elyadow

В Лиспе список из символов и чисел

А в других строка

Ты не видишь разницы?

Принципиальной — нет.

anonymous
()
Ответ на: комментарий от elyadow

Ну так схемнюки ж тоже про гомоиконность пердят, вместе с прочими скобкодрочерами.

anonymous
()
Ответ на: комментарий от elyadow

Суть в том, что (loop for i from 1 to 10 sum i) парсится так же, как, например, (+ x y z 1 a 10 b c), а именно — список из символа, символа, символа, символа, числа, символа, числа, символа и символа.

Ок, представим гипотетический макрос (loop «for i from 1 to 10 sum»). Теперь цикл не парсится лиспом, он передается строкой, а макрос должен сам его распарсить. Я ничего не упускаю, теперь это новый синтаксис?

no-such-file ★★★★★
()
Ответ на: комментарий от antares0

Вобще loop это библиотека

Ну так и (do ...) библиотека, в CL вообще все циклы можно раскрывать в tag/go. В лиспе нет синтаксиса для циклов?

Так для примера будет довольно сложно написать синктаксический корректный, но неверный семантически пример

Если следовать твоей логике, то (loop azaza) синтаксически корректная лисп-форма.

[1]> (loop azaza)

*** - LOOP: некорректный синтаксис около AZAZA в (LOOP AZAZA)

Ну надо же.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Цикл и так не парсится Лиспом, об чем я и сообщал. Так что ты упустил все, кроме фиги.

elyadow
()
Ответ на: комментарий от no-such-file

В лиспе нет синтаксиса для циклов?

Разве это не общеизвестно?

Если следовать твоей логике, то (loop azaza) синтаксически корректная лисп-форма.

Оно не корректно семантически, но с точки зрения синтаксиса именно лиспа, а не вложеных DSL, все на месте.

Так для примера будет довольно сложно написать синктаксический корректный, но неверный семантически пример

Если следовать твоей логике, то (loop azaza) синтаксически корректная лисп-форма.

У меня такое впечетление что мой пост ты так и не прочитал. Я понимаю что слов было многовато, но видимо я зря старался донести свою мысль.

antares0 ★★★★
()
Ответ на: комментарий от monk

На том уровне, где в лиспе список символов и чисел, в другом языке список токенов.

Нет. Это если речь идет о (f x y z) получается список, а если будет (f x y (g h) z) - будет дерево же. То есть там где в лиспе дерево из символов, чисел и т.д., там в других языках АСТ.

Это тоже Common Lisp:

Это ридермакросы.

anonymous
()
Ответ на: комментарий от anonymous

А в других строка

В лиспе тоже строка. Вопрос в том, как из этой строки получается АСТ.

anonymous
()
Ответ на: комментарий от no-such-file

Ок, представим гипотетический макрос (loop «for i from 1 to 10 sum»). Теперь цикл не парсится лиспом, он передается строкой, а макрос должен сам его распарсить. Я ничего не упускаю, теперь это новый синтаксис?

А если мы возьмем сишку, в которой функции loop передается описание цикла, то это тоже будет новый синтаксис сишки?

anonymous
()
Ответ на: комментарий от no-such-file

Если следовать твоей логике, то (loop azaza) синтаксически корректная лисп-форма.

Так и есть:

* (read)
(loop azaza)

(LOOP AZAZA)
*
как видишь - ридер корректно все распарсил и вернул АСТ.

Ну надо же.

Это ошибка ф-и loop, а не ридера. Если ты в сишке запустишь какой-то парсер, то он тоже может кинуть ошибку «блаблабла в строке Х позиции Y ошибка», это же не значит что код на сишке не валидный? Наоборот - уже тот факт что парсер отработал говорит о том, что код валиден, что АСТ построено, скомпилировано и запущено.

anonymous
()
Ответ на: комментарий от anonymous

которой функции loop передается описание цикла, то это тоже будет новый синтаксис сишки?

Очевидно, что описание цикла будет иметь какой-то синтаксис, не обязательно сишечки.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

Это ошибка ф-и loop, а не ридера. Если ты в сишке запустишь какой-то парсер

Т.е. loop запускает какой-то парсер, который работает с новым синтаксисом? Что и требовалось доказать.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

loop берет AST

for i from 1 to 10 sum i - это AST? Разупорись, балаболка, это просто список лексем. loop делает токенизацию лексем и парсит токены самостоятельно.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Очевидно, что описание цикла будет иметь какой-то синтаксис, не обязательно сишечки.

Но мы добавляем этот синтаксис в сишку, значит это будет новый синтаксис сишки, так? И, тогда, в любом языке можно расширять синтаксис, да?

anonymous
()
Ответ на: комментарий от no-such-file

Т.е. loop запускает какой-то парсер, который работает с новым синтаксисом? Что и требовалось доказать.

В любом языке можно запускать парсер, который работает с новым синтаксисом. Значит в любом языке можно вводить новый синтаксис. Это требовалось доказать?

anonymous
()
Ответ на: комментарий от no-such-file

for i from 1 to 10 sum i - это AST?

Это элементы AST языка лисп. Корень - loop, это его элементы. Ты хоть раз писал парсер языка? Как бы ты написал парсер для лиспа представляешь себе? Вот это оно. На выходе твого парсера было бы дерево, одним из узлов которого был бы loop с его «детьми».

это просто список лексем

С точки зрения парсера языка lisp это дочерние элементы loop'а. То, что loop с ними что-то делает - это уже этап семантического анализа, который в лиспе расширяется с помощью макросов.

loop делает токенизацию лексем и парсит токены самостоятельно.

Он не делает токенизацию. То, что делает loop - это его личные тараканы, он может брать элементы AST и по ним строить совсем другое AST, по другим правилам «грамматики», но это уже не парсер лиспа и не синтаксис лиспа.

Блин, попробуй написать свой компилятор, может тогда поймешь, о чем речь.

anonymous
()
Ответ на: комментарий от no-such-file

for i from 1 to 10 sum i - это AST?

Это АСТ, именно так.

Разупорись, балаболка, это просто список лексем.

Нет, неверно. Это дерево. Список лексем не может быть деревом.

loop делает токенизацию лексем и парсит токены

Неверно. loop не принимает список токенов, loop принимает АСТ. Ты понимаешь разницу между деревом и списком? А как вообще происходит построение АСТ, компиляция? По-видимому нет, потому что иначе такой бред бы не писал.

anonymous
()
Ответ на: комментарий от anonymous

Но мы добавляем этот синтаксис в сишку, значит это будет новый синтаксис сишки, так?

Не так, в сишке парсинг происходит в рантайме, а не при компиляции.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

Нет, неверно. Это дерево

Охренительно. И где у этого дерева корень?

Список лексем не может быть деревом

А это именно список.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от anonymous

В любом языке можно запускать парсер, который работает с новым синтаксисом. Значит в любом языке можно вводить новый синтаксис. Это требовалось доказать?

Это утверждение верно. Например Qt (moc)

Но в лиспе парсер имеет доступ ко всем функциям лиспа. Включая те, которые определены в обрабатываемом файле.

monk ★★★★★
()
Ответ на: комментарий от anonymous

loop не принимает список токенов, loop принимает АСТ

Повторяй эту молитву 33 раза в час. И не токенов, а лексем, loop сам присваивает им токены.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

С точки зрения парсера языка lisp это дочерние элементы loop'а.

Видишь ли какая штука... Что является точкой зрения лисп, определяет парсер внутри макроса.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

И не токенов, а лексем, loop сам присваивает им токены.

Ну и бредятина. А тут:

(loop for i from 1 to 16
    do (format t "~D, " (fibonacci i))
    finally (format t "...~%"))

Покажи мне поток лексем для макроса loop.

anonymous
()
Ответ на: комментарий от no-such-file

Что является точкой зрения лисп, определяет парсер внутри макроса.

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

anonymous
()
Ответ на: комментарий от anonymous

Покажи мне поток лексем для макроса loop

Не поток, а список.

> (defmacro f(&rest list) (list (quote quote) list))
F
> (f for i from 1 to 16 do (format t "~D, " (fibonacci i)) finally (format t "...~%"))
(FOR I FROM 1 TO 16 DO (FORMAT T "~D, " (FIBONACCI I)) FINALLY (FORMAT T "...~%"))
Каждый элемент списка - лексема. (FORMAT T «~D, » (FIBONACCI I)) целиком для loop лексема, он её не смотрит внутрь, а использует как есть.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

Еще раз, любой макрос в лиспе берет AST

Ещё раз, не любой. И ещё раз, если тебя смущает, что разбивка на лексемы производится не макросом, рассмотри макрос который принимает параметр в виде строки и сам её режет на лексемы.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Каким образом структура может быть лексемой? Ты с ума сошел? Там поддерево AST.

Ты реально упорот. Иди читай теорию от SICP и книгам по Common Lisp'у, до книги дракона и пр. литературе по компиляторам. Ты не понимаешь, что такое лексер, парсер и пр. Нихрена не знаешь.

anonymous
()
Ответ на: комментарий от no-such-file

Ещё раз, не любой

Любой. В том числе loop.

рассмотри макрос который принимает параметр в виде строки и сам её режет на лексемы.

Он будет принимать AST, которая будет состоять из одного элемента, со строковым значением, доставать оттуда значение и парсить его. Но это его личное дело, что он делает. С точки зрения языка программирования, макросу просто отдается AST, а что он там делает - пофиг. Главное, чтобы вернул корректный AST.

anonymous
()
Ответ на: комментарий от no-such-file

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

anonymous
()
Ответ на: комментарий от no-such-file

Не так, в сишке парсинг происходит в рантайме, а не при компиляции.

И что? Можешь считать, что он происходит в рантайме, просто компилятор делает тривиальную оптимизацию и переносит вычисление константного выражения в компайлтайм.

anonymous
()
Ответ на: комментарий от no-such-file

Во время компиляции - не в любом.

Если компилятор сишки оптимизирует эту функцию, выведя в компайлтайм, то отсюда следует что ты добавил новый синтаксис в сишку?

anonymous
()
Ответ на: комментарий от no-such-file

Охренительно. И где у этого дерева корень?

loop у него корень. Остальное - листья.

А это именно список.

Нет, это дерево. Ты не можешь отличить дерево от списка?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.