«А, у вас компилятор заново строит результатное выражение, да? Т.е. если в
образце — скобки, и в результатном выражении — скобки, то скобки в результатном
выражении будут созданы заново? Тогда тяжело. В принципе, если навострить
компилятор брать скобочные термы из образца и вставлять их (или их копию) в
результатное выражение, то всё получится автоматически.»
Смотря какой компилятор. Рефал-5λ без оптимизаций в результатной части всё
строит заново, кроме переменных (s-переменные, по-моему, копирует всегда, не
помню). При компиляции с ключом -OR используется модифицированный алгоритм
жадного строкового замощения, по максимуму использующий узлы из аргумента. При
этом узлы он может при необходимости переинициализировать, например, превращать
скобку в символ или символ в скобку. Если в образце есть (Ident e.Name) и в
результате есть (Ident e.Name), то в режиме оптимизации, скорее всего, этот
фрагмент аргумента не развалится. Однако, гарантий нет. Например, для
предложения
F {
(Ident e.Name1) (Ident e.Name2) = (Ident e.Name1) () (Ident e.Name2);
}
он может выделить куски «(Ident e.Name1) (» и «Ident e.Name2)». Или, хуже того,
выделит кусок «(Ident e.Name1) (Ident» и второй «Ident» превратит в «)».
Алгоритм жадный ведь. А второй «(Ident» в результате может сделать из узлов
«<F», переинициализировав угловую скобку в круглую и ссылку на функцию «F» в
идентификатор «Ident».
Рефал-05 для простоты реализации заново аллоцирует всё, кроме t- и e-переменных
(я делал замеры, s-переменные дешевле копировать всегда, т.к. перешивание
двунаправленного списка накладнее, чем переинициализация узла).
Да, обе реализации используют классическое списковое представление.
Если делать оптимизирующий компилятор с массивным представлением или
представлением с подвешенными круглыми скобками, то семантику из предыдущего
письма сделать будет проще.
«4.3. Хотелось бы уметь переходить к оригинальным версиям термов в функциях,
вызываемых из „линзированной“ функции. Как это сделать красиво, я не придумал.»
Линзирование может быть вложенным. Скажем, для того же лексического анализа
первая линза может устранять координаты, вторая — устранять атрибуты, оставляя
только теги доменов. Поэтому термы могут быть незалинзированы (если обе линзы
его не меняли), залинзированы однократно одной или другой линзой и
залинзированы двукратно (от них будет тянуться цепочка длины два).
Я бы предложил использовать встроенную функцию с именем «|»:
<| терм> — разлинзирует однократно,
<|| терм> — двухкратно,
<||| терм> — трёхкратно и т.д.
Разлинзировать можно неограниченное количество раз, т.к. если линзы кончились,
терм перестаёт меняться.
Я правильно понял, что если линза трансформировала терм, то на выходе он
восстановится, а если удалила, то уже нет?
Кстати, уже в третий раз замечаю, что Вы предпочитаете добавлять к объектным
выражениям неявные атрибуты, т.е. невидимые для сопоставления с образцом —
выражения, сопоставимые с одноимёнными переменными могут иметь разные атрибуты:
1. Функции, приписываемые к идентификаторам в Рефале-7.
2. Индексы-словари, приписываемые к подвыражениям для ускорения
ассоциативного поиска.
3. И здесь незалинзированные термы.
Недостаток неявных атрибутов в том, что выражения, сопоставимые с одноимёнными
переменными, могут вести себя по-разному. Это усложняет программирование на
языке и затрудняет написание оптимизирующих компиляторов. Программист вынужден
учитывать, что где-то могут быть подвешены атрибуты, и писать код так, чтобы
компилятор их не потерял. Это напоминает копирование переменных, но если
копирование влияет только на эффективность, то потеря атрибутов (в случае
функций и, особенно, в случае линз) может менять поведение программы. Учёт
атрибутов также усложнит глубокие оптимизации, да и вообще генерацию кода.
From: Sergei Skorobogatov s.yu.skorobogatov_AT_gmail.com <[email protected]>
Sent: Friday, November 15, 2024 12:39 AM
To: [email protected]
Subject: Re: Синтаксис словарей в Рефале!
On Thu, Nov 14, 2024 at 10:56 PM Александр Коновалов a.v.konovalov87_AT_mail.ru
<http://a.v.konovalov87_AT_mail.ru> <[email protected] <mailto:[email protected]> >
wrote:
«При выполнении линзы к термам, которые она выдаёт наружу, добавляется
информация о том, каким исходным термам они соответствуют. Достаточно при этом
аннотировать только те термы, которые отличаются от исходных.»
Я так понимаю, что каждая функция должна компилироваться в двух режимах: в
режиме линзы, когда она добавляет к термам аннотации, и в режиме линзированной
функции (который ещё и общий случай), когда аннотации должны сохраняться (см.
следующий абзац). Если функцию не удалось откомпилировать в первом режиме (она
не соответствует синтаксическим требованиям, см. предыдущий абзац), то в её
описателе добавляется соответствующий флаг и попытка использовать её в роли
линзы приводит к аварийному завершению программы.
Да, так и есть. К счастью, в реальных программах необходимым условиям "линзы"
будут соответствовать не так много функций. А те функции, которые случайно
соответствуют, но не используются в качестве "линз", будут, скорее всего,
маленькими. И поэтому особого раздувания кода не жду.
On Thu, Nov 14, 2024 at 10:56 PM Александр Коновалов a.v.konovalov87_AT_mail.ru
<http://a.v.konovalov87_AT_mail.ru> <[email protected] <mailto:[email protected]> >
wrote:
«Надо только следить, чтобы код, порождённый компилятором для „линзированной“
функции, не потерял аннотации термов.»
Собственно, вопрос в том, когда компилятор должен переносить аннотацию с терма
из образца в терм результата.
А, у вас компилятор заново строит результатное выражение, да? Т.е. если в
образце -- скобки, и в результатном выражении -- скобки, то скобки в
результатном выражении будут созданы заново? Тогда тяжело. В принципе, если
навострить компилятор брать скобочные термы из образца и вставлять их (или их
копию) в результатное выражение, то всё получится автоматически.