Добрый вечер, Александр!

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

Да, это было у Турчина в «пятитомнике» препринтов о языке Рефал. Переменные, 
сопоставление с которыми приводит к вызову функции, там назывались 
«рекурсивными». Они ни разу не были реализованы, на сколько мне известно.

Одной из наиболее распространённых потребностей в рекурсивных переменных была 
потребность в ограничении множества значений термов, сопоставимых с переменной. 
Например, «эта s-переменная может сопоставиться только с буквой», «эта 
e-переменная может сопоставиться только с последовательностью цифр», «эта 
s-переменная не может быть равна символу 'ERR'», «эта v-переменная (непустая 
e-переменная) состоит только из макроцифр» и т.д. Данную задачу успешно решали 
спецификаторы, появившиеся в Рефале-2.

Позже, в Рефале-5 появились условия, которые по возможностям были сравнимы со 
спецификаторами, поэтому в Рефале-5 и последующих диалектах (кроме одного, см. 
далее) ничего, подобного спецификаторам, не появлялось. Практика показала, что 
условия и эквивалентные им конструкции в Рефале-6 и Рефале Плюс дают 
удовлетворительный результат.

Рефал-6 (не Рефал-6b, о котором недавно писал Николай, а тот, который развил и 
поддерживает Аркадий Климов) содержит понятия «действия» и «неуспехи». В письме 
я рассказывать про них не буду, отошлю к документации, которая достаточно 
прозрачна. В Рефале-6 есть возможность выразить и связку «или» (как блок с 
несколькими предложениями), и связку «и» (как несколько условий), и связку «не» 
(есть отрицания действий), и скобки (усиления и ослабления неуспехов).

Вариативность в левой части образца в Рефале-6 можно выразить следующим образом:

F {
  e.Name 〈что-то ещё〉, e.Name { 'Маша' = ; 'Саша' = } = … ;
  … = …;
};

Если в синтаксисе что-то напутал, Аркадий Валентинович может поправить.

Аналогичная функциональность есть и в Рефале Плюс, но только там синтаксис и 
семантика сложнее. Одной из целей Рефала Плюс было написание языка, который был 
бы замкнут относительно суперкомпиляции полного Рефала (возможно даже, это была 
основная цель). Но результат суперкомпиляции выражается не в виде программы на 
Рефале, а в виде графа суперкомпиляции, существенно более низкоуровневой 
конструкции. Поэтому диалект Рефал Плюс обладает рядом низкоуровневых средств 
вроде функций с несколькими аргументами и результатами (полные покрывающие 
функции в это прокрустово ложе не ложатся) с ограничениями на их использование 
(несоответствие формату вызывает ошибку компиляции), тонкими средствами 
управления потоком выполнения — заборами, отсечениями, прозрачными и 
непрозрачными блоками и прочим. В общем, то, что оптимизирующий компилятор в 
идеале должен делать неявно, программист в Рефале Плюс может прописать явно. 
Рефал-6 гораздо более высокоуровневый язык, он допускает программирование как в 
низкоуровневом стиле Рефала Плюс, так и в высокоуровневом стиле Рефала-5. И его 
понять гораздо проще. Я сам сначала разобрался в Рефале-6, а потом в Рефале 
Плюс.

Вариативность (но с ущербом для эффективности) можно реализовать и в Рефале-5. 
Код, эквивалентный коду Рефала-6, будет выглядеть так:

F {
  e.Name 〈что-то ещё〉, <F-Name e.Name> : T = … ;
  … = …;
}

F-Name {
'Маша' = T;
'Саша' = T;
e.Other = F;
}

В Рефале-5λ тоже самое можно записать компактнее за счёт синтаксического сахара:

F {
  e.Name 〈что-то ещё〉
    , e.Name
    : {
        'Маша' = T;
        'Саша' = T;
        e._ = F;
      }
    : T
    = … ;

  … = …;
}


Теперь возвращаюсь к тому «одному диалекту». Это диалект Refal-D, предложенный 
Маратом Шамильевичем Исламовым. Он отчасти наследует от Рефала-5 (условия 
остались, блоки выкинуты), однако в языке был существенно расширен синтаксис 
правых частей. Множества значений переменных в нём можно задавать фактически 
при помощи грамматик, заданных в БНФ. В частности, пример с Машей-Сашей на нём 
можно записать так:

F {
  { 'Маша' | 'Саша' }.Name 〈что-то ещё〉 = … ;
  … = …;
}

Доступна презентация об этом языке:

http://freeschool.altlinux.ru/wp-content/uploads/2010/02/islamov_presentation.pdf

Есть описание диалекта в рефал-сборнике:

http://refal.botik.ru/library/refal2015_issue-II.pdf

Есть репозиторий исходных текстов:

https://github.com/mislamov/refal51

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


А вообще, для данной конкретной задачи можно написать так:

F {
  e.Name 〈что-то ещё〉, ('Маша') ('Саша') : e.1 (e.Name) e.2 = … ;
  … = …;
}

Если писать в базисном Рефале, без условий, то так:

F {
  e.Name 〈что-то ещё〉 = <F1 ('Маша') ('Саша') (e.Name 〈что-то ещё〉)> ;
  … = …;
}

F1 {
  e.1 (e.Name) e.2 (e.Name 〈что-то ещё〉) = …;
  … = …;
}

Имя для функции F1, на мой вкус, плохое, но в зависимости от задачи можно 
подобрать и более подходящее имя.


С уважением,
Александр Коновалов


From: Александр Гусевgusev_aleksandr_AT_mail.ru 
Sent: Saturday, March 27, 2021 10:37 PM
To: refal 
Subject: Регулярные выражения слева

Коллеги,
Прошу извинения, если я просмотрел что-то, но давно возник вопрос, ответа пока 
не увидел.

При обработке текстов весьма удобно иметь вариантность в левой части образца, 
которую дают регулярные выражения. Например, конструкция 
(Маша|Саша)
В выражении за одно обращение позволяет выбрать либо одно либо другое имя.
На Рефале-2 это будет два образца, по одному на имя.
‘Маша’ ...=...
‘Саша’ ...=...
Возможным решением вижу использование функций без побочных эффектов в левой 
части. Помню упоминание о такой возможности где-то в препринтах Турчина.
Другой вариант - встроить рег.выражения в Рефал. Мне это нравится меньше, так 
как оно «не родное», смешиваются параллельные технологии, что не очень хорошо. 
Вариант с функциями в левой части также может сильно усложнить понимание кода, 
когда нужно быстро разобраться.
Подскажите, пожалуйста, возможно есть и используются другие решения этой 
задачи, мне не очевидные. Речь идёт, конечно, о компактных решениях. Как модно 
решить задачу длинно, понятно.
  • Ref... nikolai . kondratiev_AT_gmail . com
    • ... nikolai . kondratiev_AT_gmail . com
    • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
    • ... nikolai . kondratiev_AT_gmail . com
      • ... Andrei Klimov andrei_AT_klimov . net
        • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
          • ... Andrei Klimov andrei_AT_klimov . net
      • ... Arkady Klimov arkady . klimov_AT_gmail . com
        • ... Александр Гусев gusev_aleksandr_AT_mail . ru
          • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
            • ... Andrei Klimov andrei_AT_klimov . net
              • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
                • ... Andrei Klimov andrei_AT_klimov . net
                • ... nikolai . kondratiev_AT_gmail . com
                • ... Александр Гусев gusev_aleksandr_AT_mail . ru
                • ... Александр Коновалов a . v . konovalov87_AT_mail . ru
                • ... nikolai . kondratiev_AT_gmail . com
                • ... nikolai . kondratiev_AT_gmail . com
                • ... Arkady Klimov arkady . klimov_AT_gmail . com
                • ... Александр Коновалов a . v . konovalov87_AT_mail . ru

Ответить