Добрый вечер, Александр! «Читая как-то информацию о Рефале в сети, наткнулся на упоминание отсутствия вложенных функций как недостатка языка.»
Интересно понять, что конкретно имелось ввиду, потому что «вложенная функция» — понятие растяжимое. В языках программирования, где вложенные функции есть (как функции высших порядков в функциональных языках или как вложенные процедуры в классическом Паскале), они характеризуются следующими свойствами: синтаксически они расположены внутри определения другой функции, область видимости ограничена той функцией, где они определены, и вложенные функции могут видеть локальные переменные окружающей функции. Вариант с клозами реализует только первые два свойства. Классический Рефал-5 содержит блоки — конструкции вида , Res : { Sent; Sent; Sent; } Их вполне можно считать вложенными функциями, хоть они и вызываются только один раз. Они действительно синтаксически находятся внутри другой функции, недоступны извне и, главное, в них доступны связанные снаружи переменные. Max { s.X s.Y , <Sub s.X s.Y> : { '−' s.d = s.Y; s.d = s.X; }; } Вложенные функции как функции высших порядков предложены Сергеем Скоробогатовым в Рефале-7: Скоробогатов С. Ю., Чеповский А. М. Разработка нового диалекта языка Refal // Информационные технологии. 2006. 9. C. 31-38. https://bmstu-iu9.github.io/Skorobogatov-Refal-7.pdf Ограниченная поддержка вложенных функций высшего порядка есть в Рефале-5λ — доступны только безымянные вложенные функции. «Под клозом понимается группа строк паттерна, начинающаяся с одного и того же символа, предпочтительно идентификатора. При вызове функции с указанием конкретного идентификатора, набор обрабатываемых паттернов сократится до строк, начинающихся с этого идентификатора.» На самом деле всё наоборот. Если почитать первый препринт Турчина о Рефале: Программирование на языке рефал. I. Неформальное введение в программирование на языке рефал. (keldysh.ru) то можно узнать следующее. Изначально, программа на Рефале была просто набором предложений, а функциональные скобки (скобки конкретизации) были «безымянными». Левая обозначалась к, правая — . (точка). (Знаки < и > Турчин стал использовать уже в Америке, там их ему на конференции предложил МакКарти.) Уже после определения скобок конкретизации на странице 35 препринта (по ссылке выше) Турчин вводит понятие детерминатива — символ после левой скобки конкретизации. А группу предложений с общим детерминативом — как функцию. Вообще, на сколько я понимаю, детерминативы введены отчасти ради эффективной реализации. В этом случае при вычислении конкретизации будут просматриваться не все предложения программы, а только несколько. Вводить кавер-функцию с несколькими подфункциями-клозами можно, такой стиль программирования на Рефале существует. Правда, иногда отдельные клозы не именуют, а просто пользуются различными непересекающимися (или что хуже, пересекающимися) форматами. Такой стиль опасен тем, что ошибившись при вызове, можно случайно вызвать не ту «подфункцию» функции. «„Авторекурсия“ — это вызов функцией самой себя, синтаксически выделяемой как „<<“ вместо „<имя_функции“. Никаких других „вольностей“ в синтаксисе тут нет.» На мой вкус, знак «<< …>» неудачный. Глаз привыкает, что знаки < и > являются парными скобками и всегда должны быть сбалансированы, их число должно быть одинаково. Я бы предпочёл какой-нибудь другой, выделяющийся знак для этой цели, например «<@ …>». Сам я когда-то подумывал о слове $REC для аналогичной цели, но сначала поленился, а потом забил — будет потерян один удобный приём отладки (см. здесь пример отладки DoFib). С уважением, Александр Коновалов From: Александр Гусевgusev_aleksandr_AT_mail.ru Sent: Thursday, March 11, 2021 1:52 PM To: refal@botik.ru Subject: Изобретение велосипеда Добрый день, коллеги! Поделюсь мыслью, показавшейся мне интересной. Читая как-то информацию о Рефале в сети, наткнулся на упоминание отсутствия вложенных функций как недостатка языка. По ходу реализации оказалось, что это не вполне соответствует действительности и такой механизм есть, хотя он не вполне явный и требует некоторой доработки. Я добавлю здесь небольшой текст из своего описания. Возможно, это будет интересно ещё кому-то. Позволил себе поупражняться в изобретении наименований, если что-то уже было сделано на этот счёт до меня, но я не знаю об этом. «Авторекурсия» — это вызов функцией самой себя, синтаксически выделяемой как «<<» вместо «<имя_функции». Никаких других «вольностей» в синтаксисе тут нет. Отрывок: При комбинации авторекурсии и идентификаторов добавляется удобное качество: локальные подфункции внутри одной функции, именуемые клозами. Под клозом понимается группа строк паттерна, начинающаяся с одного и того же символа, предпочтительно идентификатора. При вызове функции с указанием конкретного идентификатора, набор обрабатываемых паттернов сократится до строк, начинающихся с этого идентификатора. Если каждый паттерн начинается с идентификатора, то функция будет натуральной кавер — функцией (НКФ, natural cover) с гарантированной ясной логикой использования клозов. Пример печати квадратов цепочки макроцифр: Cover { Square s.1 = <Mul s.1 s.1>; Line = <Prout 'Конец списка'>; Line e.1 = <Prout '=' e.1>; = <<Line>; s.1 = <<Line <<Square s.1>>; s.1 e.1 = << s.1> << e.1>; }; То же, но в «классическом» варианте: Square { s.1 = <Mul s.1 s.1>; }; Line { = <Prout 'Конец списка'>; e.1 = <Prout '=' e.1>; }; Cover { = <Line>; s.1 = <Line <Square s.1>>; s.1 e.1 = <Cover s.1> <Cover e.1>; }; НКФ можно даже оптимизировать на уровне выполнения — сократить перебор вариантов без участия программиста на Рефале. Это вопрос на перспективу. С уважением, Александр Гусев gusev_aleksa...@mail.ru