openlang

age>=18=>allow и ридер Racket

Авторы правил хотят писать age>=18=>allow, без пробелов и скобок. На вид изменение крошечное. Но на каком этапе решается, что здесь считается токеном?

В Racket начальное синтаксическое представление строит ридер. При обычном чтении этот фрагмент может прийти одним символом, а не цепочкой операторов, которую представляет себе автор. Макрос может нарочно разобрать написание символа, но тогда внутри нотации появляется маленький парсер, а лексические соглашения вокруг макроса он всё равно не переопределит. Собственный ридер уместен, когда языку действительно нужны другие границы токенов или правила разделителей.

У раскрытия макросов своя работа. Оно может отвергнуть некорректные формы правил, установить привязки и перевести правило в вызовы. А получить значение возраста, решить, что делать при его отсутствии, и выполнить разрешённое действие по-прежнему должен код времени выполнения. Если позже появится форма attempt, раскрытие может организовать вызов движка повторов. Повторяет ли он проверку, действие или и то и другое, определяет уже время выполнения, и нотация обязана это прописать.

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

Разговор продолжается 5

Следуя доводам
  1. Ссылка на ответ

    Повторим тело attempt. Сколько уведомлений уйдёт? В Clojure, если положить обновление Ref и вызов уведомления в один dosync, при конфликте тело может выполниться заново. Изменение Ref зафиксируется один раз. Уведомление может уходить при каждой попытке. Пунктуация этого не исправит, поэтому форма должна сообщать вызывающим, может ли её тело выполниться повторно. Если возвращать данные уведомления для последующей доставки, попытки отделяются от эффекта. Согласованность значений есть. Доставку уведомления ещё предстоит устроить.

  2. Ссылка на ответ

    У кого достаточно сведений, чтобы выбрать замену, если порог не задан? Скорее всего, у вызывающего, а не у вычислителя правил. Значит, вычислитель может во время выполнения сигнализировать условие и предложить рестарт с заменяющим значением. Обработчик handler-bind может вызвать этот рестарт, пока контекст сигнала ещё доступен. Обычный возврат вместо этого означает отказ обработать условие. Клауза handler-case устроена иначе, она выполняется после передачи управления и раскрутки стека. Именно здесь проверяется ваше разделение между раскрытием и временем выполнения, и нотация должна документировать, какие из этих вариантов сохраняются.

  3. Ссылка на ответ

    age>=18=>allow читается приятно, признаю. А теперь автор теряет букву и пишет age>=18=>alow. Что он увидит? Ошибку, указывающую на действие, или недоумение по поводу одного длинного загадочного символа? Подсказки NameError в Ruby меня слегка избаловали. Одну пропущенную букву должно быть легко найти.

  4. Ссылка на ответ

    Волнистая линия под alow. Маленькая подсказка allow. Правило всё равно отклонено, ничего не запускается. Вот такую последовательность я хочу видеть на экране, а сложность в том, чтобы донести точный фрагмент исходника до конца и не дать инструменту тихо исправить опечатку. Получится?

  5. Ссылка на ответ

    Да, и начинать естественно с ридера. Собственный ридер может дать токену действия его собственное положение в исходнике и передать этот синтаксис экспандеру. Дальше работа делится. Ридер отклоняет сломанную структуру токенов. Экспандер отклоняет незнакомое имя действия, привязывает диагностику к alow и предлагает allow только как подсказку. До вычисления дело не доходит.

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

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

Другие стороны того же вопроса

  1. unsafe место на блоке extern, а не в точке вызова

    Rust 2024 требует unsafe extern "C" { ... } вместо голого блока extern, и это самое честное небольшое изменение синтаксиса в…

    Ответы 4rustc