LINUX.ORG.RU

документ по читателю (reader-у)

 , , , ,


1

3

Написал очень маленький документик про чтение. Содержательное в нём - расширения чтения (макросы чтения). Запрашиваю впечатления от лисперов-кложеров-растеров-схемеров.

вот он

★★★★★

Зачем ты это написал?

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

В теме теги стоят - Common Lisp, Clojure, Scheme, Rust. Ты знаешь хотя бы один из этих языков? Или Nemerle, скажем. Если проще всего сказать, то наверное, это про препроцессор.

Но вне контекста лиспа сложно понять.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от den73
  • Это документация по языку, краткая справка, заметка на полях, или что-вообще?
  • Для кого создается этот документ?
  • Какая целевая аудитория у Лиспа с кириллическим синтаксисом?

Периодически с Guile (Scheme) заигрываю.

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

Это заготовка части спецификации языка. Создаётся для всех желающих. Третий вопрос вряд ли имеет отношение к данной теме. Тут всё просто: тебе интересно - ты участвуешь. Нет - не участвуешь.

Если ты имеешь понятие о Guile, то ты наверное и знаешь, есть ли там dispatch macro characters или иные способы изменения «читателя». Я со схемой имел дела слишком давно и не помню уже.

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

В таком виде (чтобы было) Кодица является просто pet-проектом, в который людям со стороны коммитить смысла никакого, если только у них не та же болезнь (в хорошем смысле). Если я вообще правильно тебя понял, «Читатель» хорошо бы заменить на простой «Интерпретатор», а «Начертание» на «Выражение».

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

«Читатель» хорошо бы заменить на простой «Интерпретатор»

Валяюсь с упрощения. Предлагаю Читатель заменить на Чукча.

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

Ты нуб штоле? Не знаешь Дениску Попова, местного изобретателя велосипедов с треугольными колесами?

anonymous
()

Вполне не плохо, нужна доработка.

gssomi ★★
()
Ответ на: комментарий от Ja-Ja-Hey-Ho

А тут-то почему не на русском?

Ого, никогда еще Штирлиц не был так близок к провалу. А если заказчики увидят вражеские буквы? Скандал!

anonymous
()

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

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

Сам ты онанiмус. Заигнорь тег «кодица» и не сри мне в глаза. Спасибо.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от GoodPerson

«Читатель» хорошо бы заменить на простой «Интерпретатор», а «Начертание» на «Выражение».

И всё будет неправильно. Читатель - это reader или же лексер.

Определение начертания в тексте дано, и это вовсе не выражение, а иное понятие. Я не знаю, как это будет на Английском. Например,

// привет
- это начертание комментария, а else - это начертание ключевого слова else. Кроме того, термин «выражение» без контекста невозможно интерпретировать. Выражение - это строчка «2+2» и оно же - структура, которую парсер построит, прочитав эту строчку. В контексте описания реализации языка нужно отличить строчку от структуры, для этого и введено понятие «начертания». Но вообще-то понятие определено в тексте.

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

И всё будет неправильно.

Определение очень сильно сбивает.

Читатель - это reader или же лексер.

А есть вообще смысл выделять отдельную сущность Читатель, если в итоге это все равно функция (прочесть что-то)?

Я Начертание как expression понял - последовательность символов, которая продуцирует какой-то value, описанные 1 и a под expression попадают. Тебе ключевые слова и управляющие символы обозвать надо?

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

Ладно, надо добавить пример для ключевого слова и тогда будет понятно, что это не выражение. Кстати, в определении переменной её имя - это _не_ выражение, с точки зрения синтаксиса языка.

А есть вообще смысл выделять отдельную сущность Читатель, если в >итоге это все равно функция (прочесть что-то)?

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

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

Гм... Если брать CL reader macros, то у тебя получается путаница в использовании слова «символ» в значениях symbol и character. И в твоём примере с ЭсКуЭль непонятно, чем это отличается от обычного вызова функции, которая парсит строку запроса.

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

Если брать CL reader macros, то у тебя получается путаница в использовании слова «символ» в значениях symbol и character.

Отнюдь. Ассоциировать reader macros не с сочетаниями букв, а именно с symbol - это такая фишка. Средство придать reader macros должную масштабируемость. Поскольку букв очень мало, а символов сколько хочешь.

Она включена в библиотеку budden-tools и кто-то (кажется, как раз monk) стащил её в библиотеку advanced-readtable. Хотя на comp.lang.lisp, если я правильно понял, были и другие корреспонденты, которые пользовались такой фичей. Я у себя в коде пользуюсь, на данный штук 10 разных символов-ридмакросов в общей сложности использовал за всю историю. Например, в программе расчёта Стирлинга символ mo:|[| используется для обращения к массиву. meta-parse:|[| служит для описания рекурсивных лексеров. Оба они спокойно уживаются в одной таблице чтения.

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

Например, я что-то слышал про читатель без побочных эффектов в Clojure, а вот есть ли в ней ридмакросы - не слышал.

Может быть, в каком-нибудь Расте, Голанге, Ракетке или Котлине сделан лучши ридер?

Попробую ещё кастануть lovesan.

И в твоём примере с ЭсКуЭль непонятно, чем это отличается от обычного вызова функции, которая парсит строку запроса.

Там написано. Можно уже во время чтения провести лексический разбор SQL. Во-первых, можно сразу найти в нём, скажем, несбалансированные одинарные кавычки и круглые скобки.

Если ридер вызывается из IDE, то можно на основании лексического анализа разрисовать ключевые слова SQL (ридер уже будет знать, что это именно SQL и ничто иное). Зарядить в работу completion по объектам базы данных, если у нас есть копия метаданных.

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

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

Определение начертания в тексте

Я правильно понимаю, что оно соответствует синтаксическому объекту в Scheme?

Только неясно тип этого объекта. Начертание с текстом и с начертанным объектом различаются? Или, как в CL, начертание от объекта отличить нельзя?

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

Начертание - это последовательность букв. Возможно, даже на бумаге или в голове. А вот прочитанные «читателем» из этих букв лексемы - это уже объект среды чтения (в обычных языках - среды компиляции).

Программист думает только о программе и не видит остального мира, поэтому не так легко заметить, что между этими вещами есть разница.

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

Понятие начертания понадобилось именно для того, чтобы можно было чётко сформулировать фразу «один и тот же символ может быть выражен в исходном тексте несколькими разными способами». Слово «выражение» или «запись» тут плохо подходят. Вот я и подобрал свободное слово с близким смыслом. Получилось: «один и тот же символ может иметь несколько начертаний». Начертание однозначно указывает, что речь идёт об исходном тексте.

Вроде странно, что это вызвало у всех недоумение, но я и сам долго доходил до осознания того, что такой термин нужен.

Гигиена - это не ридер, а уже система макросов. Думаю, что в первой версии их может не быть. Есть лишь возможность импортировать макросы лиспа в язык. Вроде этого хватает пока что. И соответственно, получается два класса программистов на «кодице» - те, кто осилил лисп (илита) и те, кто не осилил (демос).

Я пока разрабатываю именно этап лексического разбора.

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

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

Начертание - это последовательность букв

Теперь понял. Невнимательно прочитал.

Тогда мои вопросы остаются с заменой «начертание» => «лексема».

А также, «начертанный объект», являющийся символом, транслируется в символ с учётом гигиены или нет?

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

Попробую сформулировать твои вопросы:

Лексема с начертанным объектом различаются?

Отличается. Лексема содержит данные о месте, где она прочитана, и о белых полях.

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

Наверное, будет и режим «чтения данных», унаследованный из CL. Здесь основная проблема, что не хватает буковок в синтаксисе.

Возможно, придётся чтение CL ограничить по возможностям и обернуть в символ-ридмакрос. Тогда этот вопрос уходит на периферию.

лексема транслируется в символ с учётом гигиены или нет?

Пока что лексема символа преобразуется в символ на этапе чтения.

А какая при чтении может быть гигиена? Запрещено создавать символы в других пакетах конструкцией а::б и а:б, вот и вся гигиена.

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

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

Вообще я решил следовать семантике CL, при таком решении все эти вопросы имеют свои простые решения с понятными последствиями. Если выдумывать всё заново, этап проектирования займёт годы, и всё равно есть риск накосячить. Лисп в этом плане не идеален, но годен.

Неплохо бы подумать, удастся ли сделать более чётко работающую систему в будущем.

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

На сегодня макросы можно импортировать из лиспа - это уже неплохо. Например, так сегодня реализованы «и» и «или».

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

Я подумал про гигиену и есть одна вещь, о которой я забыл. Если я стёр из определения модуля функцию f, то после пересборки модуля она должна исчезнуть. Более того, если на неё есть ссылка, то должно выдаться сообщение о том, что функция не определена.

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

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

А касаемо локальных переменных, в принципе можно усложнить пространства имён. Чтобы в

(in-package :я)
(defun щ (ё) ё)
(defun ю (ё) ё)
появлялось два пакета «я@щ» и «я@ю» и два символа «я@щ::ё» и «я@ю::ё».

Правда, тогда теряется ортогональность читателя. Но я так понимаю, что в Рэкете её и так нет?

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

в принципе можно усложнить пространства имён

В идеале (при правильно реализации) это становится гигиеной. Вот детали: http://docs.racket-lang.org/reference/syntax-model.html#(part._id-model)

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

Соответственно, контекст определения должен поддерживать читатель.

(let ((x 1))
  (let ((x 2))
    (displayln x))
  (displayln x))

содержит два разных идентификатора x.

ортогональность читателя

Это что такое?

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

Ортогональность состоит в том, что читатель читает просто дерево из атомов, не заморачиваясь его смыслом. Фаза чтения чётко отделена от фазы анализа смысла прочитанного.

Код - это данные, до тех пор, пока за него не взялся компилятор.

Понимать, что x может означать разное в разных контекстах - это уже задача компилятора.

Все иксы, прочитанные в одном пакете - это один и тот же символ.

Мне кажется, что и в racket так сделано.

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

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

Вообще я решил следовать семантике CL

В семантике CL разделение лексемы и символа избыточно.

Следовать везде, где её не нужно заменить на что-то лучшее. Лексемы нужны, поскольку нужно привязывать информацию о местоположении. К символу не привяжешь, если он встречается в файле несколько раз.

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

Все иксы, прочитанные в одном пакете - это один и тот же символ.

Мне кажется, что и в racket так сделано.

Там сначала идёт чтение: получаются лексемы с пустым контекстом. Потом проставляются метки контекста. Потом раскрытие макросов. При раскрытии макросов метки могут меняться. И только потом лексемы превращаются в объекты (символы, числа, строки, ...).

И метки контекста позволяют IDE показать ссылки именно на нужный идентификатор (навожу мышку на идентификатор — вижу стрелки использования). А также адекватно переименовывать:

В

(let ((x 1))
  (let ((x 2))
    (displayln x))
  (displayln x))
тыкаю в верхний «x», выбирают «переименовать в...» и пишу «y».

Получаю

(let ((y 1))
  (let ((x 2))
    (displayln x))
  (displayln y))

В CL такая функциональность практически невозможна.

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

К символу не привяжешь, если он встречается в файле несколько раз.

Вообще-то, было бы желание: (setf (get sym 'pos) (cons (current-position) (get sym 'pos)))

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

Вообще-то, было бы желание: (setf (get sym 'pos) (cons (current-position) (get sym 'pos)))

Только немного неудобно будет, например, найти лексему по строке и столбцу.

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

немного неудобно будет, например, найти лексему по строке и столбцу.

В этом контексте хэш позиция -> лексема и хэш позиция -> символ использовать одинаково удобно. А перебирать все лексемы и все символы одинаково неудобно.

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

У меня лексемы в списке, в лексеме есть строчка и колонка. Дерево синтаксического разбора обвешивается этой гирляндой и всё удобно. Но это получается уже не лисп. Я убеждён, что для исходников мой вариант лучше. Для данных он слишком тяжеловесен.

Ладно, у меня, наверное, перерыв до пятницы.

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