Добрый день, Александр!
К сожалению, обзора разных диалектов Рефала я нигде не встречал. Диалекты и реализации Рефала не совсем корректно называть «ветками» или «версиями», они разрабатывались независимо, общей кодовой базы, на сколько я знаю, не имеют, имеют разный синтаксис, построены на разных принципах и идеологиях (особенно, Рефал Плюс).
Сам я его могу написать, но, наверное, не сегодня. И, если напишу, то он будет неизбежно субъективным. Но обсудить будет весело.
В выходные тогда напишу, если никто не напишет раньше меня.
С уважением,
Александр Коновалов
From: Александр Гусев gusev_aleksandr_AT_mail.ru <re...@botik.ru>
Sent: Thursday, February 14, 2019 9:59 AM
To: ref...@botik.ru
Subject: Re[4]: Немного статистики
Спасибо, Аркадий!
А существует где-то краткая информация по сравнению веток рефала? Статья, может быть какая-то.
А то есть рефал-2, рефапл-5, рефал-6 и рефал-плюс - это только те, что поименованы.
У каждой версии свои сторонники и блюстители. Или всё-таки придётся в каждую вникать?
Среда, 13 февраля 2019, 20:41 +03:00 от Arkady Klimov arkady.klimov_AT_gmail.com <re...@botik.ru>:
Здравствуйте, Александр!
Прошу прощения за некоторую задержку, пришлось немного повозиться, приводя в порядок версию дистрибуции. В принципе, есть все на сайте refal.net, но сильно старое, с тех пор довольно много было правок. Вот та страничка:
Документацию (описание языка) смотрите там, в ней ничего нового.
А дистрибутив пока у меня в дропбоксе возьмите:
Как и раньше, инструкция в help/readme.txt.
Главное - распакуйте в папку ...ref6, пропишите ее в PATH и откорректируйте путь в ri.bat соответственно.
Затем вызовите test/hello.bat.
В ближайшее время надеюсь переправить его на сайт, а также обновлю архивы исходников там.
Рефал-часть почти не изменилась с тех пор, а вот С-часть обновилась существенно.
Спрашивайте, не стесняйтесь, если будут проблемы.
С уважением,
Аркадий Климов
пт, 8 февр. 2019 г. в 23:43, Александр Гусев gusev_aleksandr_AT_mail.ru <re...@botik.ru>:
Аркадий, Спасибо за ответ!
Да, я читал переписку, не до самых глубин, конечно.
Пока прошу актуальную ссылку на Рефал-6 - почитать и хоть что-то попробовать, если возможно. Вроде Hello, world на трёх языках.
То, что я имел ввиду о музыке, это тоже формульные вычисления, конечно.Возможно, но наверно уже на "символьном уровне", до которого еще надо входной сигнал поднять.
С уважением,
Александр Гусев
gusev_a...@mail.ru
--
С уважением,
Александр Гусев
gusev_a...@mail.ru
--
С уважением,
Александр Гусев
gusev_a...@mail.ru
Прошу прощения, не ответил на второй вопрос в письме.
«У каждой версии свои сторонники и блюстители. Или всё-таки придётся в каждую вникать?»
Лучше сами прочитайте учебники к основным диалектам (Рефал-2, Рефал-5(λ), Рефал-6, Рефал Плюс) и выберите тот, который Вам интересен.
Ссылка на учебник к Рефалу Плюс на http://refal.ru кривая. Правильные ссылки:
http://wiki.botik.ru/Refaldevel/RefalPlus
https://pat.keldysh.ru/~roman/doc/2006-Gurin_Romanenko--Yazyk_programmirovaniya_Refal_Plyus--ru.pdf
Документация к Рефалу-5λ пока не готова (и долго не будет готова), поэтому даю ссылку на презентацию с обзором:
https://github.com/bmstu-iu9/refal-5-lambda/blob/master/doc/Язык%20и%20компилятор%20Рефал-5λ.pdf
В презентации предполагается, что читатель знает Рефал-5.
В общем, изучайте реализации, выбирайте ту, которая Вам больше нравится либо начинайте писать свою :-).
С уважением,
Александр Коновалов
Добрый день, Леонид!
Спасибо за хорошую идею. Постараюсь в выходные написать простейший подобный компилятор.
Стоит уточнить задачу: есть ли переменные, какие знаки операций поддерживаются, на сколько подробными должны быть сообщения об ошибках, должен ли компилятор восстанавливаться…
С уважением,
Александр Коновалов
А существует где-то краткая информация по сравнению веток рефала? Статья, может быть какая-то.
Переменные есть, числа можно взять целые и вещественные. Можно упростить, на вход поступают только правильные арифметические выражения. Программа должна быть короткой, на страницу. У меня такая программа на рефале-2 была, постараюсь переслать.
Добрый день, Леонид!
Написал свой вариант на Рефале-5. Писал так, как привык писать компиляторы: подробно, без побочных эффектов и с восстановлением после ошибок. Получилось ожидаемо длинно. И медленно, поскольку в приоритет ставил читабельность (как я её понимаю), а не производительность.
Вещественные числа делать поленился, их много возни разбирать без спецификаторов. Если хотите — допишу.
Обошёлся без спаривания скобок, поскольку не знаю, зачем оно здесь нужно.
Субъективный разбор основных диалектов напишу позже.
Да, кстати, можно эту тему дать на курсовую работу. Спасибо. Сохранил себе.
Александр Коновалов
Как я там писал?
«Сам я его могу написать, но, наверное, не сегодня. И, если напишу, то он будет неизбежно субъективным. Но обсудить будет весело.»
Собственно, субъективный обзор. Выбор рассматриваемых диалектов тоже будет субъективным. Я не ставлю целью обучить программировать на каждом из диалектов, поэтому, если что непонятно (а оно будет непонятно) — читайте учебники и справочники к соответствующим языкам.
(Получилось очень длинно. Интересно, кто-нибудь дочитает до конца?)
Для начала кратко о себе, дабы обозначить точку зрения, откуда этот обзор будет выполняться. Мне нравится тема разработки компиляторов и мне нравится язык программирования Рефал, поэтому я занимаюсь тем, что пишу компиляторы Рефала на Рефале. Предпочитаю чистое функциональное программирование — без глобальных переменных и мутабельных структур данных, поэтому на них буду останавливаться подробнее.
Бенчмарки к разным реализациям не делал, поэтому оценивать быстродействие не буду. Также принципиально пишу по памяти, в источники не лезу (поэтому ссылок не будет). Поскольку пишу по памяти, могу напутать и ошибиться. Поправляйте!
Рефал-2
Я видел только реализацию, которую поддерживает Леонид Белоус, поэтому буду говорить о ней. В том смысле, что реализацию Леонида Эйсымонта не видел.
К Рефалу-2 я читал только руководство и запускал тестовые примеры из дистрибутива. Программировать на нём не пробовал.
Синтаксис Рефала-2 напоминает о временах перфокарт. Одна строка — одно предложение, знак переноса — + в конце строки. Если я ничего не путаю, длина строки ограничена 76 символами (потому что колонки 77–80 использовались для нумерации перфокарт). Или я это путаю с описанием метакода-Б из одного из препринтов Турчина.
Предложения состоят из образца и результата, разделённых знаком равенства. Нет ни условий, ни блоков, ни других вкусностей.
Имена переменных могут состоять из одного символа — буквы или цифры. По мне этого мало, но другие программисты считают, что этого достаточно. Вызов функции записывается как k/F/ аргумент. или <F аргумент>. Есть поддержка сопоставления справа-налево. Имена функций и целые числа нужно обрамлять знаками /, например, /add/, /42/. Типы переменных — S — символ, W — терм (символ или выражение в скобках), E — произвольное выражение, в том числе и пустое, V — непустое произвольное выражение.
Сильная сторона языка — спецификаторы. Можно для переменных указывать множества значений, которые она может принимать, причём можно явно перечислять, можно использовать дополнения до множества, можно записывать объединения множеств. Точный синтаксис не помню, а документацию скачивать лень.
Поддерживается длинная арифметика — числа представлены цепочками макроцифр, макроцифры лежат в диапазоне 0…224−1.
Есть мутабельные структуры данных — глобальная копилка, статические и динамические ящики. Копилка — глобальный ассоциативный массив. Статические ящики — функции-глобальные переменные, при вызове возвращают аргумент предыдущего вызова. Динамические ящики создаются во время выполнения программы, доступны по ссылке. Для динамических ящиков делается сборка мусора.
Есть поддержка вычислений в «песочнице». Функция-песочница принимает ссылку на функцию и её аргумент. Если функция вычислилась успешно, то функция-песочница возвращает код успешности (какое-то число) и её результат. Если функция упала (ошибка отождествления или недостаток памяти) — возвращается код ошибки.
Компилятор формирует исходники на ассемблере (FASM вроде), их затем нужно откомпилировать и слинковать с рантаймом. Компилятор написан на Си, поэтому работает быстро. На самом деле является «полукомпилятором», поскольку исходники ассемблера содержат не машинный код, а определения данных (инструкции db, кто знает ассемблер, поймёт) — интерпретируемый код. А рантайм содержит интерпретатор этого кода.
Есть хорошо документированный интерфейс с языком Си — можно писать встроенные функции/машинные операции (я их предпочитаю называть «нативными функциями»).
Исходники открыты. Поддерживается Windows и, вроде, Linux.
Промежуточное представление объектных выражений — классическое «плоское» списковое. Скобочные термы представлены как «узел-левая скобка» — содержимое скобок — «узел-правая скобка», узлы-скобки содержат указатели друг на друга. А это значит, что если в правой части какая-то W-, V- или E-переменная упоминается больше раз, чем в левой, то дополнительные экземпляры строятся путём копирования. И время копирования пропорционально длине записи значения этих переменных (иначе говоря, количеству узлов списка).
Рефал/2
Независимая реализация Рефала-2, написанная Василием Стеллецким для себя. Я в ней разбирался, поэтому о ней тоже напишу несколько слов.
Является полукомпилятором: состоит из компилятора в язык сборки и интерпретатора языка сборки. Компилятор написан на себе, интерпретатор на Си.
Реализация ориентирована на русскоязычную DOS/Windows, в частности, поддерживаются имена функций и переменных русскими буквами в кодировке 866. Размер поля зрения ограничен 32 килобайтами, что для задач Василия является достаточным (о чём он недавно писал). Спецификаторы переменных очень ограничены — поддерживается или множество символов-литер, или дополнение до этого множества. Вызов функции записывается как k/F/ arg. или к/F/ arg. Т.е. левую скобку конкретизации можно записывать и кириллицей (в 866).
В процессе компиляции выводит листинг на экран, при обнаружении синтаксической ошибки выводит о ней сообщение и останавливается. При некоторых синтаксических ошибках (довольно редко) вылетает с дампом поля зрения — соответственно, вместо сообщения имеем малопонятный дамп. Понятно лишь, что что-то не так в последней строчке.
Есть порт под Linux.
Исходники открыты, довольно компактны. Мне было достаточно интересно разобраться в этой реализации.
Промежуточное представление данных — классическое плоское списковое.
Ещё есть где-то на GitHub’е интерпретатор Рефала-2, написанный какими-то чуваками из МГУ. С чуваками не знаком, ихнюю реализацию не изучал и даже не скачивал, поэтому о ней ничего не напишу.
Лирическое отступление. В ветке дискуссии обсуждалось универсальное AST, в которое можно компилировать разные диалекты Рефала. Если в него компилировать Рефал-2, потребуется как-то изображать спецификаторы переменных.
Рефал-5
На мой взгляд — классическая, «дефолтовая» реализация Рефала. Если говорят о Рефале, то чаще всего подразумевают Рефал-5. Например, Рефал-5 рассматривал Бойко Банчев в статье для последнего номера журнала «Практика функционального программирования», Рефал-5 рассматривался в главе, посвящённой Рефалу в книжке Николая Николаевича Непейводы «Основания программирования». Из всех диалектов Рефала больше всего известны Рефал-5 и Рефал-2 (на сколько я замечал)
В ней используется синтаксис, ставший стандартом де факто в последующих реализациях Рефала — с фигурными скобками для записи функций, с именами переменных вида t.Имя (ранее был допустим вариант и tX — без точки с одной буквой), с точками с запятой в конце предложений, свободной записью программы. Виды переменных тоже классические — s, t, e — символ, терм, произвольное выражение (типа непустых выражений нет).
В начале 2000-х синтаксис Рефала-5 менялся. Запретили имена переменных без точки, ввели регистрозависимость, разрешили имена функций и идентификаторы с маленькой буквы, ввели идентификаторы (составные символы) в двойных кавычках и ряд других деталей. Из-за чего русскоязычный перевод учебника Турчина устарел.
Поддерживаются только три типа символов: символы-литеры, символы-слова (составные символы) и символы-числа (макроцифры). Длинная арифметика такая же, как и в Рефале-2, только основание системы счисления — 2³².
В предложениях поддерживаются условия и блоки. Условие — возможность наложить на образец некоторое ограничение в виде сопоставления некоторого выражения со вспомогательным образцом. Блок — вызов безымянной функции в правой части. Предложение с условием оформляется как
P, R1 : P1 = R;
Здесь на образец P наложено условие — R1 : P1. Правая часть предложения R выполняется тогда, когда найдена подстановка переменных в P такая, что результат вычисления R1 может быть сопоставлен с образцом P1. Соответственно, в R1 могут входить переменные из P, в R — переменные из P и P1.
Предложение с блоком имеет вид
P, R : { P1 = R1; P2 = R2; … };
Здесь при успешном сопоставлении с P вычисляется R и выполняется безымянная функция (записанная блоком) с аргументом, который является результатом вычисления R. При этом и в образцы P1, P2… и в результаты R1, R2… могут входить переменные из образца P. Если сопоставление R ни с одним из образцов P1, P2… не оказалось успешным, то программа падает с ошибкой отождествления.
Понятно, что условия и блоки можно комбинировать между собой — у образца может быть несколько условий, оно при этом может оканчиваться на блок, внутри блока могут быть условия и блоки и т.д.
Есть классическая копилка. Статических и динамических ящиков нет.
Язык компактный и лёгкий для понимания из-за свой ограниченности.
(Этот абзац можно пропустить.) Есть средства поддержки метавычислений — функции Mu, Dn, Up, Ev-met и две недокументированные. Mu позволяет вызвать функцию по имени из области видимости записи вызова функции и (недокументировано) среди всех entry-функций программы. Например, <Mu Add 1 2> вызовет <Add 1 2>. Функции Dn, Up и Ev-met работают с метакодом — выражениями языка Рефал общего вида (со скобками активации и переменными), записанными в виде объектных выражений. Dn переводит обычное выражение в метакод. Up берёт закодированное выражение (без переменных) и его вычисляет. Например, <Up ('!' Add ('*' '-' 1) 42)> вычислит выражение <Add ('-' 1) 42>. Ev-met может выполнять выражение в метакоде с переменными, т.е. фактически символьно вычислять некоторое обобщённое выражение + возможности песочницы.
Язык реализован как полукомпилятор: компилятор порождает интерпретируемый код, который затем выполняется интерпретатором. Интерфейса с языком Си не предусмотрено — программист ограничен набором встроенных функций. В принципе, исходники открыты, так что можно сделать и свою версию интерпретатора с нужными встроенными функциями, но это сразу делает разработанные программы не переносимыми.
Исходная реализация (компилятор и интерпретатор) написаны на Си, работают быстро. Есть реализация компилятора (crefal.rsl), написанная на Рефале, я ей почти не пользовался. Реализация на Рефале умеет оптимизировать вычисление условий для последнего предложения (см. второй том «Сборника трудов по функциональному языку программирования Рефал» под редакцией Андрея Немытых).
Представление объектных выражений — классическое плоское списковое.
Мне кажется, Рефал-5 разрабатывался как язык для написания суперкомпиляторов Рефала и вообще исследований по суперкомпиляции. В частности, функция Ev-met предназначена для ускорения суперкомпиляции и она реально использовалась в SCP3 (в SCP4 не используется). Этим можно объяснить и общую ограниченность библиотеки встроенных функций, и отсутствие мутабельных структур данных, кроме копилки. Но это моё личное мнение.
Рефал Плюс
На Рефале Плюс я не программировал, даже его не скачивал. Зато внимательно читал документацию.
Синтаксис языка развивает синтаксис Рефала-5 (не Рефала-2). Т.е. тоже фигурные скобки, точки с запятой, длинные имена переменных… Но наследует он не (только) от Рефала-5, но и от Рефала-4. От Рефала-5 он взял синтаксис, от Рефала-4 — семантику.
В Рефале-5, если у образца есть условие, была найдена подстановка переменных в образце и условие не выполнилось, то сначала ищется другая подстановка (удлинения открытых переменных), а если таковой нет, то выполнение передаётся на следующее предложение. В Рефале Плюс неуспех в выполнении условия был обобщён в неуспех вообще. В частности, неуспехи теперь могут возвращать и функции как результат своего выполнения, и блоки (записанные как \{ … }), если ни одно предложение не выполнилось. Ещё неуспехи можно усиливать (чтобы они не перехватывались в некоторой части предложения) и ослаблять. Ради управления всеми этими неуспехами придуман сложный синтаксис с такими понятиями как «хвост», «тропа», «источник», «отсечение», «забор», «развилка» и т.д. Очень поэтичные названия конструкций, мне нравятся.
Помимо образцовых блоков (как в Рефале-5), там есть и результатные блоки. Каждое предложение (вернее, тропа) в них начинается не с образцового выражения, а результатного. Эти результатные выражения, как правило, служат условиями — если одно вернуло неуспех, управление передаётся на следующее. Пример:
F sX sY
, {
<LT? sX sY> = <Print 'X < Y'>;
<GT? sX sY> = <Print 'X > Y'>;
= <Print 'X = Y'>;
};
Да, если функция состоит из одного предложения, фигурные скобки можно не писать.
И вообще, образцовые блоки формально являются синтаксическим сахаром над результатными блоками. R : { P1 = R1; P2 = R2; … } ≡ R :: eX, { eX : P1 = R1; eX : P2 = R2; … }
Ещё в Рефале Плюс используется массивное представление — представление с дорогой конкатенацией. А это значит, что если функция получает, скажем, символ, два выражения и терм, то вот так вызывать её накладно: <F s1 e2 (e3) t4> — потребуется выполнить дорогую конкатенацию — построить массив из 1 + |e2| + 1 + 1 элементов и туда скопировать s1, e2, ссылку на скобочный терм и t4.
Что же делать? Можно, конечно, выбирать такой формат <F s1 (e2) (e3) t4> — конкатенация будет, но за константное время. И придётся построить два скобочных терма. Но ради эффективность ещё более усложнили язык (как будто неуспехов мало) — ввели форматы функций. Для каждой функции нужно указывать формат аргумента и формат результата:
$func F s1 e2 (e3) t4 = (e5) e6 (e7);
Теперь при вызове <F s1 e2 (e3) t4> вообще не выполняется ни конкатенаций, ни построений скобочного терма. Для разбора значений функций в язык ввели ещё и присваивания, конструкции вида R :: He, где жёсткое выражение He должно совпадать с форматом выражения R (или обобщать его).
В общем, на первый взгляд, синтаксис сложный. Но, если понять, то всё становится просто и красиво.
Язык Рефал-4 был придуман Сергеем Романенко (не знаю, были ли его реализации, или он остался лишь нотацией) как расширение полного базисного Рефала, на котором выразима прогонка, о чём написал два препринта (они легко находятся). И в нём были и неуспехи, и условия, и результатные блоки (но не было образцовых блоков), заборы с калитками (усиления и ослабления неуспехов). А в препринтах были формулы, по которым можно выполнить прогонку функции на Рефале-4 (к сожалению, формулы неалгоритмизируемые или неалгоритмизированные). Так что синтаксис Рефала Плюс имеет цельный математический фундамент.
Собственно, весь Рефал Плюс вытекает из (а) теоретических основ Рефала-4 и (б) массивного представления данных с дорогой конкатенацией (но дешёвым копированием). Если это понять, то всё красиво и ничего сложного.
У языка богатая библиотека. В ней поддерживаются в том числе мутабельные вектора, динамические ящики, про ассоциативные массивы не помню. Есть статические ящики — глобальные переменные.
Реализации Рефала Плюс за последнее время уже несколько раз обсуждали — есть старая на Си в машинный код, есть новая самоприменимая в Си и Java, отсылаю читателей к архиву рассылки.
Сам язык создаёт ощущение развитого промышленного языка программирования. Жалко только, что не используется.
Рефал-6
На сколько мне известно, Рефал-6 появился в Переславле-Залесском (ИПС РАН) как альтернативная реализация Рефала-5, но потом он попал в руки Аркадия Климова. И Аркадий стал добавлять в язык разные возможности из Рефала Плюс: неуспехи, результатные блоки, управление неуспехами (усиление, ослабление, инверсия). В синтаксис введено понятие действия — оно может пополнять среду переменными, изменять текущее выражение и формировать неуспех. Образцовые действия текущее выражение не изменяют, пополняют среду переменными из образца. Результатные не меняют среду, но меняют текущее выражение.
F {
e.1 'x' : 'x' e.2 = xx;
e.2 = <WriteLn 'Hello'> = <WriteLn 'World'>;
}
Первое предложение принимает либо строку 'x', либо строки, которые начинаются и кончаются на 'x'. Во втором предложении идут подряд два результатных действия — возвращаемое значение первого игнорируется.
Благодаря понятию действия синтаксис языка существенно проще, чем у Рефала Плюс.
Представление объектных выражений списковое с подвешенными скобками. Каждому терму соответствует отдельное звено списка, в звене скобочного терма находится ссылка на подвыражение. Благодаря чему копирование выражений дешевле, чем в плоском списковом — время создания копии пропорционально не длине записи, а количеству термов. t-переменные копируются за константное время. Но, с другой стороны, иногда бывает неочевидно, когда выражения копируются, а когда переносятся.
На данный момент есть реализация Рефала-6 только для Windows, на unix-like переносить её, вроде, не пробовали (Аркадий Климов поправит).
Тоже полукомпилятор: компилирует в промежуточный код (в виде сериализованных данных в текстовой форме), который затем выполняется интерпретатором. Написан на себе. Когда-то запускал Рефал-5 и Рефал-6 на 486 машине, первый выполнялся мгновенно, второй с заметной задержкой.
Интерпретатор динамичный — в процессе работы может загружать и выгружать модули, можно на лету править код функций (даже отладчик, вроде, написан на Рефале).
Есть библиотека встроенных мутабельных типов данных: динамические ящики, вектора, битовые вектора (надо смотреть в документации, уже забываю). Все они имеют общий объектно-ориентированный интерфейс. Вообще, библиотека у него богатая.
Реализация «запечатана» как и Рефал-5 — пользователь ограничен набором встроенных функций, реализованных в интерпретаторе. Однако, исходники доступны и при необходимости можно написать свои встроенные функции.
Рефал-Java
Диалект Рефала-6 (диалект диалекта). Написан братьями Климовыми (кто-то из них недавно писал, что большую часть кода написал Аркадий).
Синтаксис такой же, как в Рефале-6, имеет только некоторые расширения для совместимости с Java, например, ключевое слово $import, кажется. Компилируется в Java. Представление объектных выражений — массивное.
Имеет удивительно гладкий и чистый интерфейс с языком Java — объектные выражения представляются массивами Object’ов, если элемент массива — массив Object’ов — то это скобочный терм. Любое другое значение — символ. Функция Рефала компилируется в метод на Java, принимающий и возвращающий массив. Возвращаемое значение null символизирует неуспех.
Рефал-7
Придуман Сергеем Скоробогатовым, наследует от Рефала-5/Рефала-6. О нём мало кто знает, поэтому всё-таки дам ссылку (тем более, что ссылку эту найти непросто):
https://mazdaywik.github.io/direct-link/refal.pdf
Важное нововведение языка — функции высших порядков (вложенные функции), которые могут быть и безымянными (как в Рефале-5λ), так и именованными. Синтаксис из Рефала-6 наследует понятие действия, поддерживает неуспехи, но средства работы с ними беднее. И образцовые, и результатные блоки выкинуты из языка. Результатные выкинуты безвозвратно, образцовые блоки заменяются действием-вызовом функции:
R -> Rt
R => Rt
Здесь Rt — некий результатный терм. Первый вариант прозрачен для неуспехов, второй — нет. Семантику можно описать так:
R -> Rt ≡ R : e.1, Rt : t.2, <t.2 e.1>
R => Rt ≡ R : e.1 = Rt : t.2 = <t.2 e.1>
В качестве Rt предлагается использовать вложенную функцию, которая является результатным термом:
R -> { P1 = R1; P2 = R2; … }
что делает конструкцию похожей на блок Рефала-5.
Публично доступных реализаций Рефала-7 нет, было несколько реализаций, сделанных совместно со студентами-дипломниками. Но они похоронены на жёстком диске Скоробогатова.
Промежуточное представление данных — векторно-списковое представление — представление с отложенной конкатенацией. О нём, к сожалению, публично доступных материалов тоже нет.
Рефал-5λ
До себя добрался. Когда-то я, дабы самому понять компиляцию Рефала в императивный код, написал самоприменимый компилятор Рефала с синтаксисом, похожим на Рефал-5. Назвал его Простым Рефалом, поскольку оно действительно был минималистичен (хоть и крив). Этот компилятор порождал исходники на Си++, которые затем компилировались плюсовым компилятором в исполнимые модули. Потом я стал добавлять в него разные возможности, одной из первых были вложенные функции (но только безымянные) из Рефала-7.
Дальше Простой Рефал уже развивался на кафедре — разные фичи (преимущественно, оптимизации) добавляли студенты на курсовых и дипломах. Так в языке появились сначала присванивания (безоткатные условия), а потом уже и нормальные условия. В реализации добавился интерпретируемый код (который отличается от кода Романенко, в худшую сторону).
Потом я подумал, что ещё один несовместимый диалект Рефала никому не нужен и я решил его сделать совместимым с Рефалом-5. Добавил ещё один front-end и переделал библиотеку встроенных функций. Так появился Рефал-5λ.
На текущий момент Рефал-5λ — это точное надмножество Рефала-5 (почти точное, нет поддержки метафункций), в котором есть безоткатные присваивания (добавленные из соображений производительности), вложенные функции, нативные вставки (возможность записать тело функции на Си++), статические ящики и некоторые другие возможности (например, $INCLUDE). Реализация умеет компилировать в файлы интерпретируемого кода, в Си++, умеет несколько оптимизаций, работает на Windows, Linux и macOS, порождает исполнимые файлы. Может компилировать в файлы с интерпретируемым кодом, которые затем можно загрузить динамически (как .dll/.so). Компиляция в .dll/.so операционной системы пока не реализована. Надеюсь, сделаю следующим летом.
Несмотря на оптимизации и компиляцию в Си++, Рефал-5λ оказывается медленнее, чем обычный Рефал-5 (мерял). То ли из-за того, что сами встроенные функции (включая длинную арифметику) написаны на Рефале, то ли из-за неудачного промежуточного кода.
Нормального руководства по языку пока нет и я не знаю, когда его напишу. Поскольку к нему приложили руку много студентов, компилятор распространяется под копирайтом кафедры.
Про два других своих проекта — Модульный Рефал и Рефал-05 — я тут писать уже не буду. И так тут много написано.
Ещё в двух словах. Маратом Исламовым разрабатывался D-Refal — диалект Рефала, наследующий от Рефала-5, но при этом допускающий спецификаторы переменных. Причём для спецификаторов предусматривалась возможность задать чуть ли не грамматику. К сожалению, компилятор и язык не был доведён до конца. В ИПС РАН когда-то разрабатывался язык FLAC, ориентированный на алгебраические выкладки. По сути он тоже является диалектом Рефала, его реализация напоминает Рефал-6. О FLAC’е написано в одном из томов «Сборника трудов про функциональный язык Рефал» под редакцией Андрея Немытых. Вроде всё.
Если я не упомянул какой-то диалект или реализацию, значит, я о них забыл или не знал. Можете меня спросить о них, что-нибудь о них напишу.
А кто дочитал — молодец!
С уважением,
Александр Коновалов
From: Александр Коновалов a.v.konovalov87_AT_mail.ru <refal@botik.ru>
Sent: Thursday, February 14, 2019 11:57 AM
To: refal@botik.ru
Subject: Сравнение веток Рефала
Добрый день, Александр!
Леонид!
«Я закрутился, да ещё думал, что ты забыл.»
Я не забыл. Я всё помню. Вот только что написал обещанный субъективный обзор.
«Напомни, пожалуйста, где про Рефал-5 попроще посмотреть.»
Не скажу навскидку, где можно кратко прочитать про Рефал-5. Могу только отослать к учебнику Турчина, но там не кратко:
http://refal.botik.ru/book/html/
Может, кто-нибудь другой подскажет более короткое описание.
(Получилось очень длинно. Интересно, кто-нибудь дочитает до конца?)
PS. Вот. только что пришло письмо, кто-то (не понял кто) уже кажется сделал это на Рефале-2.
Добрый вечер, Андрей!
Наконец-то началась дискуссия вокруг моего материала. На все письма отвечу, но позже (завтра или вечером).
А что гадать-то? swi@cnshb.ru — Стеллецкий Василий Игоревич из Центральной Научной Сельско-Хозяйственной Библиотеки.
А вообще, нужно просто подписывать письма.
С уважением,
Александр Коновалов
From: Andrei Klimov andrei_AT_klimov.net <re...@botik.ru>
Sent: Monday, February 25, 2019 8:29 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
On Mon, Feb 25, 2019 at 8:14 PM Arkady Klimov arkady.klimov_AT_gmail.com <re...@botik.ru> wrote:
$func? EX sN eS = eS;
EX \{0 eS = eS;
sN eS , 'abc' : e sX e , sX eS :: eR, # \{ eR : vA vA e; }, <EX <Sub sN 1> eR>;};
$func EX1 sN eS = eS;EX1 sN eS, sN eS : {
sN vA vA e = <Next sN eS>;
0 e = eS;sN e = <EX1 <Sub sN 1> 'a' eS>;};$func Next sN eS = eS;Next {sN = ();sN sX eS = {
'abc' : e sX sY e = <EX1 sN sY eS>;
= <Next <Add sN 1> eS>;};};
EX1 sN eS : {
// Goal!
0 e = eS;
// eS is unacceptable
sN vA vA e = <Next sN eS>; // tail recursion, eS is not empty (otherwise previous sentence works)
...
Нет ли тут каких эффектов, что если мы по длинному списку бежим быстрее (меньше действий), то все начинает работать медленнее? Может из-за каких-то свойств кэша?
Уважаемые господа!
Добрый вечер, Аркадий!
Вы писали:
«Сейчас у меня появилась мысль, и хочу всем апологетам того или иного диалекта её предложить: написать небольшой текст в свободной форме на 2-3-5 страниц с описанием особенностей их „любимых“ версий языка и их реализаций — что было бы полезно знать потенциальным пользователям.»
Я вспомнил! У меня же есть такой текст про Рефал-5λ и называется он (кто бы мог подумать!) README:
https://github.com/bmstu-iu9/refal-5-lambda (сразу после списка файлов)
В нём описываются цели проектирования компилятора + отличия от «классического» Рефала-5, под которым я подразумеваю refc/refgo актуальной версии. Только на сайт refal.ru выложить этот материал пока не получится — на нём нет раздела про Рефал-5λ. J
С уважением,
Александр Коновалов
P.S. На письма рассылки, пришедшие ко мне с воскресенья, я помню и на них отвечу. Возможно, в выходные.
From: Arkady Klimov arkady.klimov_AT_gmail.com [mailto:re...@botik.ru]
Sent: Thursday, February 14, 2019 4:31 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
Я не успел вовремя заметить появление новой ветки, поэтому теперь копирую сюда свой ответ Александру Гусеву (с небольшими стилистическими правками).
---------------------------------------------------------------------------------------------------
А существует где-то краткая информация по сравнению веток рефала? Статья, может быть какая-то.
Насколько я знаю, в каком-то законченно-оформленном виде такой информации сейчас нет.
Сейчас у меня появилась мысль, и хочу всем апологетам того или иного диалекта ее предложить: написать небольшой текст в свободной форме на 2-3-5 страниц с описанием особенностей их "любимых" версий языка и их реализаций - что было бы полезно знать потенциальным пользователям. Эти тексты (ссылки) можно было бы разместить на сайте refal.net на страницах, связанных с каждой версией-диалектом. В этой переписке по Рефалу+ уже много информации появилось, осталось ее собрать и оформить. Наверно, это было бы полезно.
А также неплохо бы единый бенчмарк составить. И какие-то сравнительные таблицы.
А еще когда-то была установка на создание единого инструментария по реализации разных диалектов с единым промежуточным синтаксисом AST, с возможностью любой входной диалект на любую платформу положить. Насколько я понимаю, Рефал+ свою часть пути в основном прошел и там это представление задокументировано. Я хотел бы пройти свою часть для Рефала-6, но на это конечно нужно время. Которого, увы, нет.
Аркадий
чт, 14 февр. 2019 г. в 12:46, Eisymont Leonid verger-lk_AT_yandex.ru <re...@botik.ru>:
Переменные есть, числа можно взять целые и вещественные. Можно упростить, на вход поступают только правильные арифметические выражения. Программа должна быть короткой, на страницу. У меня такая программа на рефале-2 была, постараюсь переслать.
14.02.2019, 12:40, "Александр Коновалов a.v.konovalov87_AT_mail.ru" <re...@botik.ru>:
Добрый день, Леонид!
Спасибо за хорошую идею. Постараюсь в выходные написать простейший подобный компилятор.
Стоит уточнить задачу: есть ли переменные, какие знаки операций поддерживаются, на сколько подробными должны быть сообщения об ошибках, должен ли компилятор восстанавливаться…
С уважением,
Александр Коновалов
From: Eisymont Leonid verger-lk_AT_yandex.ru <re...@botik.ru>
Sent: Thursday, February 14, 2019 12:33 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
Будет действительно весело. А делать надо, дождались. Рекомендую взять какой - нибудь пример и на нем это сравнивать. Иначе будет пустой болтовней. А вот какой пример - пока не соображу, м.б. перевод арифметических выражений в линеаризованную польскую запись, например, в триады? Но этот перевод должен начинаться с лексического анализа со спариванием скобок. Обычно перевод в польскую запись хорошо воспринимался на лекциях по рефалу. Кстати, рефал-2 рассказывался обычно за десять-пятнадцать минут, даже чиновникам и генералам. Сколько потребуется времени на рассказ о "коллапсирующих джунглях" подумать страшно. Вот она жизнь и заскорузлая практика.
Добрый день, Александр!
К сожалению, обзора разных диалектов Рефала я нигде не встречал. Диалекты и реализации Рефала не совсем корректно называть «ветками» или «версиями», они разрабатывались независимо, общей кодовой базы, на сколько я знаю, не имеют, имеют разный синтаксис, построены на разных принципах и идеологиях (особенно, Рефал Плюс).
Сам я его могу написать, но, наверное, не сегодня. И, если напишу, то он будет неизбежно субъективным. Но обсудить будет весело.
В выходные тогда напишу, если никто не напишет раньше меня.
Реализация на http://www.refal.net/diaspora.html упомянута «В.Стеллецкий, ЦИиТЭИагропром, Москва»
Да. В dos-овском варианте было так. И было такое же ограничение на списковую память (но это даже больше, чем было на БЭСМ-6 ;) ).
Недавно сделал еще версию с динамически выделяемой памятью по 1К по мере надобности. Иначе бы такие тесты выполнить бы не смог.
Длинная арифметика мне понадобилась только для работы с файлами (длина файла в одну макроцифру не помещается). Но я реализовал только сложение, вычитание и полусумму…
С уважением,
Василий Стеллецкий
--
Vasily Stelletsky mailto:s...@cnshb.ru mailto:sw...@ya.ru
http://www.cnshb.ru/vniitei/sw/ http://sw710.narod.ru
From: Arkady Klimov
arkady.klimov_AT_gmail.com [mailto:re...@botik.ru]
Sent: Wednesday, February 27, 2019
3:28 PM
To: re...@botik.ru
Subject: Re: Сравнение веток
Рефала
Василий, спасибо,
Добрый день, Аркадий!
Пока не надо туда выкладывать мой дистрибутив, поскольку документации как таковой нет, есть только недописанный учебник. А без документации выкладывать некрасиво.
С уважением,
Александр Коновалов
Добрый день, Василий!
Кстати, Ваша реализация тоже фигурирует в моём обзоре реализаций Рефала. Реализация Красовского и Белоуса там упомянута как Рефал-2, Ваша — как Рефал/2. В первом случае чёрточка между «Рефал» и «2» горизонтальная (дефис), во втором — наклонная (дробь).
Странно, что Аркадий задал этот вопрос, ведь он же читал мой обзор.
Кстати, Василий, только сейчас подумал: можно ли читать название Вашей реализации «Рефал/2» как «Рефал пополам» или «полуРефал»?
С уважением,
Александр Коновалов
Прошу прощения, давно смотрел реализацию и забыл. Запомнилось, что 32 килочего-то, небольшой (по современным меркам) фиксированный объём поля зрения.
Про реализацию Веденова (или Ведёнова, не знаю) мне рассказывали, что в своё время она была самой быстрой реализацией Рефала. И он свои исходники никому не показывал. Но вот с Василием, оказывается, поделился.
С уважением,
Александр Коновалов
Добрый день, Василий!
Кстати, Ваша реализация тоже фигурирует в моём обзоре реализаций Рефала. Реализация Красовского и Белоуса там упомянута как Рефал-2, Ваша — как Рефал/2. В первом случае чёрточка между «Рефал» и «2» горизонтальная (дефис), во втором — наклонная (дробь).
Добрый вечер, Андрей!
Не знал про эту историю слешей, дефисов, пробелов и ничего в качестве разделителя версии языка.
Сейчас версии обычно отделяют пробелом: Java 6, Python 2, Python 3. Для Python часто уточняют версию «официального» интерпретатора — Python 2.7 — не только сама программа-интерпретатор, но и версия языка, реализованная в нём. Альтернативные реализации Python (вроде PyPy, IronPython) могут говорить — «мы поддерживаем Python 2.7», например.
Для языков со стандартом часто указывают год принятия стандарта — C89, C++98, C99, C11, C++11, C++14, C++17 ← для Си и Си++ без пробела.
Для языков Н. Вирта я встречал обозначения только с дефисом: Модула-2, Оберон, Оберон-2, Оберон-07.
В документации к реализации Красовского и Белоуса и в большинстве ссылок на неё (в том числе, на сайте Василия http://www.cnshb.ru/vniitei/sw/refal/default.htm — справа-сверху) используется дефис. Василий, говоря о своей реализации, использует дробь. Поэтому я их в обзоре различал по дефису и дроби J.
С уважением,
Александр Коновалов
From: Andrei Klimov andrei_AT_klimov.net <re...@botik.ru>
Sent: Wednesday, February 27, 2019 6:36 PM
To: refal@botik.ru
Subject: Re: Сравнение веток Рефала
On Wed, Feb 27, 2019 at 3:58 PM Александр Коновалов a.v.konovalov87_AT_mail.ru <re...@botik.ru> wrote:
Юра!Ты нигде не написал, какой у тебя был аргумент. 10000?А ошибку я тоже у себя нашел, спасибо.АркPS. У себя на Рефал6 нашел странности.Для начала проверил, что отождествление vA vA e транслируется также как и ta eA ta eA e.Это нормально. Но поиск старого терма делается без оптимизаций, на общих основниях.Поэтому поменял образец на sa eA sa eA e, надеясь, что будет оптимизированное удлинение.Не тут то было. Посмотрел компилятор - оптимизация не работает, хотя присутствует, но то ли с ошибкой, то ли с сознательной блокировкой (какой-то ид OVSYM вместо OSYM стоит).Разблокировал. Странлировал.Время работы для 10000 упало вдвое (0.54 сек). Отлично. Но дальше полезла чертовщина.С увеличением N время стало расти не квадратично, как раньше, а круче!И для 100000 стало медленнее чем раньше (114 сек вместо 100). Это я уже не понимаю.Нет ли тут каких эффектов, что если мы по длинному списку бежим быстрее (меньше действий), то все начинает работать медленнее? Может из-за каких-то свойств кэша?
Добрый день!Пример Аркадия на Рефал+:$func? EX sN eS = eS;EX \{0 eS = eS;sN eS , 'abc' : e sX e , sX eS :: eR, # \{ eR : vA vA e; }, <EX <Sub sN 1> eR>;};Я ошибся. По умолчанию в компиляторе были выключены оптимизации и включен режим отладки. Теперь время около 0.62 секунд.Пример с двумя iter из документации в приложении. Требует heap'а чуть поменьше (1ГБ против 2ГБ). Считает 10.5 секунд.
Кстати, Антон, а правильно я понимаю, что в нынешней реализации Р+ при отождествлении образцаvA vA eпервая vA удлиняется только до половины длины аргумента?
Мда, как я понял, код для eR : vA vA e далек от оптимальности.На каждое очередное удлинение первой vA:1. Проверяем, что не дошли до конца eR.2. Вычисляем длину vA (len6) и длину дополнения vA до eR (len5).3. Проверяем, что не (len5 < len6) -- этим обеспечивается удлинение до половины4. Вычисляем разницу len5-len6 (это будет длина остатка e)5. Вызываем сравнение vA и ее дополнения до eR -- тут я не понял, надо чтобы eV было не равно дополнению, а было началом дополнения, а где это сказано?
В общем, довольно много всего. Поэтому не удивительно, что только чуть-чуть обгоняет рефал-6, в котором удлинение происходит всегда до конца eR (даже без оптимизации удлинения до старого символа).А надо бы: вне цикла разделить длину eR пополам, перед вызовом функции сравнения цепочек быстро сравнить первые термы и не вычислять прежде времени длину остатка e.
Да, 1.5%, не густо. В принципе, конечно, пусть дальше думает С++.Но текущий вряд ли догадается чего-то вытащить из функции.А в Р6 v-переменные еще на входе заменяются на t e, поэтому первые термы отдельно сравниваются.И поэтому накладные на подготовку цикла сравнения (vA vA e) уже не столь значимы.
Правда, обратный образец (e vA vA) будет смертоубийством: удлинений справа нет.А у вас, наверно, равноценно, да?
RF_lsplit (_ve_R, 0, _ve__dollar_tmp_m_6_m_51, _v_lsplit__R);
for ( ; ; RF_iter(_ve_R)++)
{
{
if (!RF_iter(_ve_R))
{
goto _negation1;
}
int _v_len5 = _v_lsplit__R.get_len ();
int _v_len6 = 0;
if (_v_len5 < (_v_len6 + 2))
{
goto _negation1;
}
if (((_v_len5 - _v_len6) % 2) != 0)
{
goto _continue2;
}
int _v_len__A = ((_v_len5 - _v_len6) / 2);
Expr _vv_A (Expr (_v_lsplit__R, 0, _v_len__A));
if (!_vv_A.eq (_v_lsplit__R, (0 + _v_len__A)))
{
goto _continue2;
}
goto _exit2;
}
_continue2: {}
}
_exit2: {}А за счёт чего получается экономия при выносе первых термов?Что переставляется при движении по выражению один указатель (на терм), а не два (на конец левого подвыражения и на начало правого)? Я не думаю, что здесь можно существенно выиграть.
День добрый, всем!
> ... По мере тасования памяти скорость падает до 2 раз.
Тема диссертации Светланы Подколзиной (Трубицыной): реализация Лиспа с
массивным представлением по направлению CDR.
CAR -- ссылка, CDR -- соседняя ячейка (близось адресов).
Тракторная сборка мусора, которая как бульдозер сдвигала все нужное,
собирая свободные ячейки в крупные массивы.
С чем боролись? Кэша тогда не было, а вот виртуальная память была. И
по мере "тасования памяти" шаг в с;едующую ячейку списка с большой
вероятностью приводил к пэйдж-фолту.
Вот с этим и боролись.
Чтобы понять, лучше ли iter чем рекурсия, я переделал последний вариант EX1 (хотя рекурсия там тоже не настоящая, хвостовая) через $iter. Антон или Юра, сможете пропустить? А то я пока не умею этого.Правда, вряд ли заметно ускорится, поскольку основное время здесь, по-видимому, уходит все-таки на образец vA vA e.// Result () indicates that such string does not exist// Iter variable sP : { T - expression eS is ok; F - eS must be rebuild; U - unknown }$func EX2 s = e;EX2 sN, T sN /* empty */ $Iter { sP eS : {T e = U <Sub sN 1> 'a' eS;U vA vA e = F sN eS;U e = T sN eS;F sa es, 'abc' : e sa sb e = U sN sb es;F sc es = F <Add sN 1> es;}} :: sP sN eS, sP sN eS : \{ T 0 e = eS; F s = (); };Чтобы выразить все через единый цикл, пришлось ввести три состояния sP, которые характеризуют имеющуюся информацию о допустимости текущей строки:T - допустима, U - неизвестно, F - недопустима или все продолжения оказались недопустимыми.
День добрый, Антон, Юра!
Я там как-то невнимательно следил.
1. Р+ с $iter должен быт лучше (не хуже) чем рекурсия. Но не сильно
(хвостовая рекурсия мало уступает $iter).
2. Р+ с рекурсией не должен жрать стек (точнее, жрать и освобождать
сразу, так как хвостовая).
Так и есть? А если не так, то поясните, плз.
Всего доброго,
Сергей Абрамов
Добрый день, Аркадий!
«Александр, поручаю Вам быть „хозяином“ этого файла, можете забрать его и выложить где-то от себя.»
Подготовил этот файл и выложил у себя в репозитории-«файлопомойке»:
https://mazdaywik.github.io/direct-link/refal-compare
Задачу Вирта для Рефала-5 я решу как-нибудь позже.
С уважением,
Александр Коновалов
From: Arkady Klimov arkady.klimov_AT_gmail.com <re...@botik.ru>
Sent: Monday, February 25, 2019 4:51 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
Я не только дочитал, наконец, но и внес свои правки-дополнения (в раздел по Рефал-6, и чуток по Рефал Плюс), поместив этот замечательный текст в doc-файл, который можно взять по ссылке:
Я подумал, что хорошо бы моему примеру последовали и "держатели" других диалектов.
Александр, поручаю Вам быть "хозяином" этого файла, можете забрать его и выложить где-то от себя. Мои добавки, помеченные цветом и префиксом "АрК", можете в своем стиле адоптировать.
Будет замечательно, если Вы сможете сделать из этого публикацию в ближайшее время. Призываю всех, кто чем может (правками, замечаниями и тп), этому посодействовать.
***
Я по ходу решил еще раз почитать документацию-руководство по Рефалу Плюс. У меня сложное отношение к нему, то есть он как-то всегда был сложен для меня. Как я сейчас понял, возможно это из-за специфического описания синтаксиса, содержащего понятия "тропы" и "хвосты". Они очень похожи, и я всегда их путал и не мог привыкнуть различать. Для этого было бы полезно видеть их семантическое различие, чем я не владею. А описание языка такового не предлагает. Остается только "зазубривать" формальные особенности, напрягая свою внутреннюю "нейросеть". Хорошо бы те, кто владеют семантическим пониманием хвостов и троп Рефала Плюс, если таковое существует, его как-то эксплицировали.
***
В руководстве мне встретился интересный пример - задача "о цепочках" (из Вирта), раздел 1.10. Надо породить строку из трех знаков (a, b, c), чтобы в ней не было одинаковых смежных подстрок.
Решение довольно мутное, тем более оно дважды использует $Iter, который я не люблю (вероятно, авторы, хотели именно его иллюстрировать этим примером). И мне захотелось переписать его в более "чистых" терминах. И вот что у меня получилось:
---------------------------------------------------------------------------------------------------------- файл abc.ref
// <EX sN eS> - расширить строку eS влево sN знаками a,b,c,
// не допуская повторов смежных подстрок
EX {
0 eS = eS;
sN eS , 'abc' : e sX e , sX eS : eR : # vA vA e, <EX <SUB sN 1> eR>;
};
------------------------------------------------------------------------------------------------------------
Это рефал-6, но думаю, можно по аналогии и на Плюсе написать (может даже и так пройдет).
Функция EX откатная, при успехе выдает продолженную строку, иначе откат. Образец e sX e перебирает три варианта продолжения, образец vA vA e под отрицанием проверяет, что выражение не начинается с двух одинаковых непустых подстрок, дальше идет рекурсивный вызов, все через запятую прозрачно для откатов.
Назвал функцию заглавными покороче, чтобы в интерактивной моде вызывать:
d:\ref6\TEST>d:\ref6\rix.exe i+abc+*ask -S1000000 -T1000000 -H1000000
#>ex 5
'acaba'
#>ex 10
'bcacbacaba'
#>ex 100
'cacbacabacbabcabacabcbabcacbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbacabacbabcacbacaba'
#>ex 1000
'acbabcacbacabacbabcbacbcabacbabcacbacabacbabcabacabcbabcabacbabcacbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcbabcacbacabacbabcbacbcabacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacabacbabcacbacabacbabcbacabacbcacbacabacbabcacbacabacbcacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacabacbabcacbacabacbabcbacbcabacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacabacbabcacbacabacbabcbacabacbcacbacabacbabcacbacabacbcacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacbcabacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacabacbabcacbacabacbabcbacbcabacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbabcabacbabcbacabacbabcabacabcacbacabacbabcabacabcbabcacbacabacbabcabacabcacbabcabacbabcacbacabacbabcabacabcacbacabacbabcacbacaba'
#>ex 10000
EVAL: *** SYSTEM: Reference counter overflow
The referenced object is: *EX
EVAL: Act Vf Fre Run [n]Step [n]Trc Evl Chg Kil New Inf M W D H cLr Quit>
Пришлось задать большой стек S и таблицу элементов Т (по 1000000 элементов, по 16 и 8 байтов соответственно), и 1 ГБ (H Kb) общей памяти, иначе стеки быстро переполнялись. Здесь на каждый следующий элемент строки вводится уровень в стеке из-за возможности откатов. Но все равно на аргументе 10000 сломалось - по переполнению счетчика ссылок на объект *EX (символ функции). По-видимому, каждый уровень стека содержал несколько экземпляров ссылок, а всего в реализации счетчик ссылок не может превысить 2^15.
Хороший тест получился. Показал некоторые пределы реализации.
Решение на Рефал Плюс из руководства тоже жадно до стека. Интересно, какие там пределы?
На получение строки наибольшей длины (около 6500) ушло чуть меньше секунды. По-видимому, на последней версии Рефала Плюс будет быстрее: либо из-за не копирований eS и eR (благодаря "дыркам"), либо из-за более оптимального отождествления vA vA e: уравнения на длинах должны ограничить удлинение переменной vA только до половины длины аргумента, а в Рефале-6 она тупо продолжает удлиняться до конца аргумента.
Надеюсь, было не скучно.
Аркадий
Добрый вечер, Андрей!
«Хотя кэши тоже стали большими и рабочие множества в задачах обработки символьной информации стали больше в них помещаться, но по идее векторное представление должно обгонять.»
Мне кажется, тут ещё и определяет сама структура данных. Например, для такой (условный пример)
t.Expr ::= s.NUMBER | (t.Expr s.Op t.Expr)
s.Op ::= '+' | '-' | '*' | '/'
большой разницы между списком и вектором не будет (в плане использования кэша). Потому что и вектора-кусочки тоже будут маленькие, и тоже могут быть рандомно рассеяны по куче. Хотя, конечно, вектор будет требовать меньше памяти, и операции с ним будут быстрее.
С уважением,
Александр Коновалов
From: Andrei Klimov andrei_AT_klimov.net <re...@botik.ru>
Sent: Friday, March 1, 2019 6:56 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
On Fri, Mar 1, 2019 at 5:17 PM Sergei M. Abramov abram_AT_botik.ru <re...@botik.ru> wrote:
Добрый вечер, Антон!
«Вообще, на мой взгляд, $iter оправдан по двум причинам:
1) Ситуации, когда рекурсия по сути хвостовая, но не является таковой из-за смежных конкатенаций: (e1 <F e2>)»
Тут решает векторно-списковое представление Скоробогатова. Позже о нём напишу отдельным письмом.
«2) Отсутствие вложенных функций/замыканий. Выносить каждый простой внутренний цикл во внешнюю функцию (передавая туда все нужные локальные переменные) — слишком тяжеловесно.»
Как пользователь Рефала с замыканиями, могу подтвердить. Наиболее частые циклические задачи — обход последовательности с преобразованием и/или с агрегацией. Для этой цели очень удобно использовать функции Map, MapAccum и Reduce, передавая в них замыкание. Но в плане быстродействия это дорого, дороже вручную написанной хвостовой рекурсии. А $iter’а у меня нет.
С уважением,
Александр Коновалов
From: Anton Orlov orlovan_AT_gmail.com <re...@botik.ru>
Sent: Saturday, March 2, 2019 10:39 AM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
On Fri, Mar 1, 2019 at 4:08 AM Sergei M. Abramov abram_AT_botik.ru <re...@botik.ru> wrote:
Аркадий задал интересный вопрос:
«Хотелось бы понять, что там на самом деле происходит (с „дырками“ слева-справа) и что мешает. И возможно ли это преодолеть в автоматическом режиме.»
Учитывает ли реализация Рефала Плюс количество ссылок на вектор? Потому что понятие «дырки» сильно зависит от владения вектором. Допустим, у нас есть такая функция:
F {
s.1 e.Middle s.2 = <G e.Middle>;
}
G {
e.X = '[' e.X ']';
}
$ENTRY Go1 {
= 'Hello' :: e.X = <Prout <F e.X>> <Prout e.X>;
}
$ENTRY Go2 {
= <Prout <F 'Hello'>>;
}
Функция F в обоих случаях отрезает от слова Hello буквы H и o, серединку ell передаёт в G, которая вокруг неё приписывает скобки, получается [ell]. Но в функции Go1 обязательно нужно создавать копию строки, а в функции Go2 копирования можно избежать.
Функция Go2 передаёт F единственный экземпляр Hello, и когда та отрезает первый и последний символ, они становятся «дырками» — никто другой их не использует. А значит, G может в них записать квадратные скобки. В функции Go1 один и тот же массив разделяется между вызовом F и Prout, поэтому перезаписать первый и последний элементы квадратными скобками в G нельзя.
Такие случаи Рефал Плюс учитывает? Потому что для того же примера с задачей Вирта в цикле то приписывается, то отрезается первый символ, но при этом у вектора всегда один владелец. А значит, при конкатенации его можно перезаписывать, а не создавать новый.
С уважением,
Александр Коновалов
From: Arkady Klimov arkady.klimov_AT_gmail.com <re...@botik.ru>
Sent: Sunday, March 3, 2019 10:36 PM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
Все это верно, но это же не имеет отношения к примеру о цепочках из учебника по Р+. Рекурсия там - не хвостовая. И как писал Юра (26.02):
Добрый вечер всем!
Помните моё длинное письмо про обзор диалектов Рефала? Я из него сделал статью:
Коновалов А. В. Обзор основных диалектов Рефала. Евразийское Научное Объединение. 2020. № 10-2 (68). С. 111-117.
https://esa-conference.ru/wp-content/uploads/2020/11/esa-october-2020-part2.pdf (стр. 34/111)
В статье учтены замечания Аркадия Валентиновича по поводу диалекта Рефала-6. Добавлены упоминания новых проектов Рефала, разрабатываемых Владимиром Гошевым и Максимом Кривчиковым (он выступал в ИПМ). Раздел про Рефал-5λ полностью переписан.
В статье есть опечатка: фразу «О нём, к сожалению, публично доступных материалов тоже нет» на стр. 38/115 следует читать как «[27]». В список литературы ссылку добавил, а текст статьи поправить забыл. Горько и обидно за этот косяк.
В том длинном письме я писал:
«Также принципиально пишу по памяти, в источники не лезу (поэтому ссылок не будет). Поскольку пишу по памяти, могу напутать и ошибиться. Поправляйте!»
В статье, наоборот, обширный список литературы из 33 источников.
С уважением,
Александр Коновалов
From: Александр Коновалов a.v.konovalov87_AT_mail.ru [mailto:re...@botik.ru]
Sent: Wednesday, February 20, 2019 8:41 PM
To: re...@botik.ru
Subject: RE: Сравнение веток Рефала
Как я там писал?
«Сам я его могу написать, но, наверное, не сегодня. И, если напишу, то он будет неизбежно субъективным. Но обсудить будет весело.»
Собственно, субъективный обзор. Выбор рассматриваемых диалектов тоже будет субъективным. Я не ставлю целью обучить программировать на каждом из диалектов, поэтому, если что непонятно (а оно будет непонятно) — читайте учебники и справочники к соответствующим языкам.
(Получилось очень длинно. Интересно, кто-нибудь дочитает до конца?)
Для начала кратко о себе, дабы обозначить точку зрения, откуда этот обзор будет выполняться. Мне нравится тема разработки компиляторов и мне нравится язык программирования Рефал, поэтому я занимаюсь тем, что пишу компиляторы Рефала на Рефале. Предпочитаю чистое функциональное программирование — без глобальных переменных и мутабельных структур данных, поэтому на них буду останавливаться подробнее.
Бенчмарки к разным реализациям не делал, поэтому оценивать быстродействие не буду. Также принципиально пишу по памяти, в источники не лезу (поэтому ссылок не будет). Поскольку пишу по памяти, могу напутать и ошибиться. Поправляйте!
Рефал-2
Я видел только реализацию, которую поддерживает Леонид Белоус, поэтому буду говорить о ней. В том смысле, что реализацию Леонида Эйсымонта не видел.
К Рефалу-2 я читал только руководство и запускал тестовые примеры из дистрибутива. Программировать на нём не пробовал.
Синтаксис Рефала-2 напоминает о временах перфокарт. Одна строка — одно предложение, знак переноса — + в конце строки. Если я ничего не путаю, длина строки ограничена 76 символами (потому что колонки 77–80 использовались для нумерации перфокарт). Или я это путаю с описанием метакода-Б из одного из препринтов Турчина.
Предложения состоят из образца и результата, разделённых знаком равенства. Нет ни условий, ни блоков, ни других вкусностей.
Имена переменных могут состоять из одного символа — буквы или цифры. По мне этого мало, но другие программисты считают, что этого достаточно. Вызов функции записывается как k/F/ аргумент. или <F аргумент>. Есть поддержка сопоставления справа-налево. Имена функций и целые числа нужно обрамлять знаками /, например, /add/, /42/. Типы переменных — S — символ, W — терм (символ или выражение в скобках), E — произвольное выражение, в том числе и пустое, V — непустое произвольное выражение.
Сильная сторона языка — спецификаторы. Можно для переменных указывать множества значений, которые она может принимать, причём можно явно перечислять, можно использовать дополнения до множества, можно записывать объединения множеств. Точный синтаксис не помню, а документацию скачивать лень.
Поддерживается длинная арифметика — числа представлены цепочками макроцифр, макроцифры лежат в диапазоне 0…224−1.
Есть мутабельные структуры данных — глобальная копилка, статические и динамические ящики. Копилка — глобальный ассоциативный массив. Статические ящики — функции-глобальные переменные, при вызове возвращают аргумент предыдущего вызова. Динамические ящики создаются во время выполнения программы, доступны по ссылке. Для динамических ящиков делается сборка мусора.
Есть поддержка вычислений в «песочнице». Функция-песочница принимает ссылку на функцию и её аргумент. Если функция вычислилась успешно, то функция-песочница возвращает код успешности (какое-то число) и её результат. Если функция упала (ошибка отождествления или недостаток памяти) — возвращается код ошибки.
Компилятор формирует исходники на ассемблере (FASM вроде), их затем нужно откомпилировать и слинковать с рантаймом. Компилятор написан на Си, поэтому работает быстро. На самом деле является «полукомпилятором», поскольку исходники ассемблера содержат не машинный код, а определения данных (инструкции db, кто знает ассемблер, поймёт) — интерпретируемый код. А рантайм содержит интерпретатор этого кода.
Есть хорошо документированный интерфейс с языком Си — можно писать встроенные функции/машинные операции (я их предпочитаю называть «нативными функциями»).
Исходники открыты. Поддерживается Windows и, вроде, Linux.
Промежуточное представление объектных выражений — классическое «плоское» списковое. Скобочные термы представлены как «узел-левая скобка» — содержимое скобок — «узел-правая скобка», узлы-скобки содержат указатели друг на друга. А это значит, что если в правой части какая-то W-, V- или E-переменная упоминается больше раз, чем в левой, то дополнительные экземпляры строятся путём копирования. И время копирования пропорционально длине записи значения этих переменных (иначе говоря, количеству узлов списка).
Рефал/2
Независимая реализация Рефала-2, написанная Василием Стеллецким для себя. Я в ней разбирался, поэтому о ней тоже напишу несколько слов.
Является полукомпилятором: состоит из компилятора в язык сборки и интерпретатора языка сборки. Компилятор написан на себе, интерпретатор на Си.
Реализация ориентирована на русскоязычную DOS/Windows, в частности, поддерживаются имена функций и переменных русскими буквами в кодировке 866. Размер поля зрения ограничен 32 килобайтами, что для задач Василия является достаточным (о чём он недавно писал). Спецификаторы переменных очень ограничены — поддерживается или множество символов-литер, или дополнение до этого множества. Вызов функции записывается как k/F/ arg. или к/F/ arg. Т.е. левую скобку конкретизации можно записывать и кириллицей (в 866).
В процессе компиляции выводит листинг на экран, при обнаружении синтаксической ошибки выводит о ней сообщение и останавливается. При некоторых синтаксических ошибках (довольно редко) вылетает с дампом поля зрения — соответственно, вместо сообщения имеем малопонятный дамп. Понятно лишь, что что-то не так в последней строчке.
Есть порт под Linux.
Исходники открыты, довольно компактны. Мне было достаточно интересно разобраться в этой реализации.
Промежуточное представление данных — классическое плоское списковое.
Ещё есть где-то на GitHub’е интерпретатор Рефала-2, написанный какими-то чуваками из МГУ. С чуваками не знаком, ихнюю реализацию не изучал и даже не скачивал, поэтому о ней ничего не напишу.
Лирическое отступление. В ветке дискуссии обсуждалось универсальное AST, в которое можно компилировать разные диалекты Рефала. Если в него компилировать Рефал-2, потребуется как-то изображать спецификаторы переменных.
Рефал-5
На мой взгляд — классическая, «дефолтовая» реализация Рефала. Если говорят о Рефале, то чаще всего подразумевают Рефал-5. Например, Рефал-5 рассматривал Бойко Банчев в статье для последнего номера журнала «Практика функционального программирования», Рефал-5 рассматривался в главе, посвящённой Рефалу в книжке Николая Николаевича Непейводы «Основания программирования». Из всех диалектов Рефала больше всего известны Рефал-5 и Рефал-2 (на сколько я замечал)
В ней используется синтаксис, ставший стандартом де факто в последующих реализациях Рефала — с фигурными скобками для записи функций, с именами переменных вида t.Имя (ранее был допустим вариант и tX — без точки с одной буквой), с точками с запятой в конце предложений, свободной записью программы. Виды переменных тоже классические — s, t, e — символ, терм, произвольное выражение (типа непустых выражений нет).
В начале 2000-х синтаксис Рефала-5 менялся. Запретили имена переменных без точки, ввели регистрозависимость, разрешили имена функций и идентификаторы с маленькой буквы, ввели идентификаторы (составные символы) в двойных кавычках и ряд других деталей. Из-за чего русскоязычный перевод учебника Турчина устарел.
Поддерживаются только три типа символов: символы-литеры, символы-слова (составные символы) и символы-числа (макроцифры). Длинная арифметика такая же, как и в Рефале-2, только основание системы счисления — 2³².
В предложениях поддерживаются условия и блоки. Условие — возможность наложить на образец некоторое ограничение в виде сопоставления некоторого выражения со вспомогательным образцом. Блок — вызов безымянной функции в правой части. Предложение с условием оформляется как
P, R1 : P1 = R;
Здесь на образец P наложено условие — R1 : P1. Правая часть предложения R выполняется тогда, когда найдена подстановка переменных в P такая, что результат вычисления R1 может быть сопоставлен с образцом P1. Соответственно, в R1 могут входить переменные из P, в R — переменные из P и P1.
Предложение с блоком имеет вид
P, R : { P1 = R1; P2 = R2; … };
Здесь при успешном сопоставлении с P вычисляется R и выполняется безымянная функция (записанная блоком) с аргументом, который является результатом вычисления R. При этом и в образцы P1, P2… и в результаты R1, R2… могут входить переменные из образца P. Если сопоставление R ни с одним из образцов P1, P2… не оказалось успешным, то программа падает с ошибкой отождествления.
Понятно, что условия и блоки можно комбинировать между собой — у образца может быть несколько условий, оно при этом может оканчиваться на блок, внутри блока могут быть условия и блоки и т.д.
Есть классическая копилка. Статических и динамических ящиков нет.
Язык компактный и лёгкий для понимания из-за свой ограниченности.
(Этот абзац можно пропустить.) Есть средства поддержки метавычислений — функции Mu, Dn, Up, Ev-met и две недокументированные. Mu позволяет вызвать функцию по имени из области видимости записи вызова функции и (недокументировано) среди всех entry-функций программы. Например, <Mu Add 1 2> вызовет <Add 1 2>. Функции Dn, Up и Ev-met работают с метакодом — выражениями языка Рефал общего вида (со скобками активации и переменными), записанными в виде объектных выражений. Dn переводит обычное выражение в метакод. Up берёт закодированное выражение (без переменных) и его вычисляет. Например, <Up ('!' Add ('*' '-' 1) 42)> вычислит выражение <Add ('-' 1) 42>. Ev-met может выполнять выражение в метакоде с переменными, т.е. фактически символьно вычислять некоторое обобщённое выражение + возможности песочницы.
Язык реализован как полукомпилятор: компилятор порождает интерпретируемый код, который затем выполняется интерпретатором. Интерфейса с языком Си не предусмотрено — программист ограничен набором встроенных функций. В принципе, исходники открыты, так что можно сделать и свою версию интерпретатора с нужными встроенными функциями, но это сразу делает разработанные программы не переносимыми.
Исходная реализация (компилятор и интерпретатор) написаны на Си, работают быстро. Есть реализация компилятора (crefal.rsl), написанная на Рефале, я ей почти не пользовался. Реализация на Рефале умеет оптимизировать вычисление условий для последнего предложения (см. второй том «Сборника трудов по функциональному языку программирования Рефал» под редакцией Андрея Немытых).
Представление объектных выражений — классическое плоское списковое.
Мне кажется, Рефал-5 разрабатывался как язык для написания суперкомпиляторов Рефала и вообще исследований по суперкомпиляции. В частности, функция Ev-met предназначена для ускорения суперкомпиляции и она реально использовалась в SCP3 (в SCP4 не используется). Этим можно объяснить и общую ограниченность библиотеки встроенных функций, и отсутствие мутабельных структур данных, кроме копилки. Но это моё личное мнение.
Рефал Плюс
На Рефале Плюс я не программировал, даже его не скачивал. Зато внимательно читал документацию.
Синтаксис языка развивает синтаксис Рефала-5 (не Рефала-2). Т.е. тоже фигурные скобки, точки с запятой, длинные имена переменных… Но наследует он не (только) от Рефала-5, но и от Рефала-4. От Рефала-5 он взял синтаксис, от Рефала-4 — семантику.
В Рефале-5, если у образца есть условие, была найдена подстановка переменных в образце и условие не выполнилось, то сначала ищется другая подстановка (удлинения открытых переменных), а если таковой нет, то выполнение передаётся на следующее предложение. В Рефале Плюс неуспех в выполнении условия был обобщён в неуспех вообще. В частности, неуспехи теперь могут возвращать и функции как результат своего выполнения, и блоки (записанные как \{ … }), если ни одно предложение не выполнилось. Ещё неуспехи можно усиливать (чтобы они не перехватывались в некоторой части предложения) и ослаблять. Ради управления всеми этими неуспехами придуман сложный синтаксис с такими понятиями как «хвост», «тропа», «источник», «отсечение», «забор», «развилка» и т.д. Очень поэтичные названия конструкций, мне нравятся.
Помимо образцовых блоков (как в Рефале-5), там есть и результатные блоки. Каждое предложение (вернее, тропа) в них начинается не с образцового выражения, а результатного. Эти результатные выражения, как правило, служат условиями — если одно вернуло неуспех, управление передаётся на следующее. Пример:
F sX sY
, {
<LT? sX sY> = <Print 'X < Y'>;
<GT? sX sY> = <Print 'X > Y'>;
= <Print 'X = Y'>;
};
Да, если функция состоит из одного предложения, фигурные скобки можно не писать.
И вообще, образцовые блоки формально являются синтаксическим сахаром над результатными блоками. R : { P1 = R1; P2 = R2; … } ≡ R :: eX, { eX : P1 = R1; eX : P2 = R2; … }
Ещё в Рефале Плюс используется массивное представление — представление с дорогой конкатенацией. А это значит, что если функция получает, скажем, символ, два выражения и терм, то вот так вызывать её накладно: <F s1 e2 (e3) t4> — потребуется выполнить дорогую конкатенацию — построить массив из 1 + |e2| + 1 + 1 элементов и туда скопировать s1, e2, ссылку на скобочный терм и t4.
Что же делать? Можно, конечно, выбирать такой формат <F s1 (e2) (e3) t4> — конкатенация будет, но за константное время. И придётся построить два скобочных терма. Но ради эффективность ещё более усложнили язык (как будто неуспехов мало) — ввели форматы функций. Для каждой функции нужно указывать формат аргумента и формат результата:
$func F s1 e2 (e3) t4 = (e5) e6 (e7);
Теперь при вызове <F s1 e2 (e3) t4> вообще не выполняется ни конкатенаций, ни построений скобочного терма. Для разбора значений функций в язык ввели ещё и присваивания, конструкции вида R :: He, где жёсткое выражение He должно совпадать с форматом выражения R (или обобщать его).
В общем, на первый взгляд, синтаксис сложный. Но, если понять, то всё становится просто и красиво.
Язык Рефал-4 был придуман Сергеем Романенко (не знаю, были ли его реализации, или он остался лишь нотацией) как расширение полного базисного Рефала, на котором выразима прогонка, о чём написал два препринта (они легко находятся). И в нём были и неуспехи, и условия, и результатные блоки (но не было образцовых блоков), заборы с калитками (усиления и ослабления неуспехов). А в препринтах были формулы, по которым можно выполнить прогонку функции на Рефале-4 (к сожалению, формулы неалгоритмизируемые или неалгоритмизированные). Так что синтаксис Рефала Плюс имеет цельный математический фундамент.
Собственно, весь Рефал Плюс вытекает из (а) теоретических основ Рефала-4 и (б) массивного представления данных с дорогой конкатенацией (но дешёвым копированием). Если это понять, то всё красиво и ничего сложного.
У языка богатая библиотека. В ней поддерживаются в том числе мутабельные вектора, динамические ящики, про ассоциативные массивы не помню. Есть статические ящики — глобальные переменные.
Реализации Рефала Плюс за последнее время уже несколько раз обсуждали — есть старая на Си в машинный код, есть новая самоприменимая в Си и Java, отсылаю читателей к архиву рассылки.
Сам язык создаёт ощущение развитого промышленного языка программирования. Жалко только, что не используется.
Рефал-6
На сколько мне известно, Рефал-6 появился в Переславле-Залесском (ИПС РАН) как альтернативная реализация Рефала-5, но потом он попал в руки Аркадия Климова. И Аркадий стал добавлять в язык разные возможности из Рефала Плюс: неуспехи, результатные блоки, управление неуспехами (усиление, ослабление, инверсия). В синтаксис введено понятие действия — оно может пополнять среду переменными, изменять текущее выражение и формировать неуспех. Образцовые действия текущее выражение не изменяют, пополняют среду переменными из образца. Результатные не меняют среду, но меняют текущее выражение.
F {
e.1 'x' : 'x' e.2 = xx;
e.2 = <WriteLn 'Hello'> = <WriteLn 'World'>;
}
Первое предложение принимает либо строку 'x', либо строки, которые начинаются и кончаются на 'x'. Во втором предложении идут подряд два результатных действия — возвращаемое значение первого игнорируется.
Благодаря понятию действия синтаксис языка существенно проще, чем у Рефала Плюс.
Представление объектных выражений списковое с подвешенными скобками. Каждому терму соответствует отдельное звено списка, в звене скобочного терма находится ссылка на подвыражение. Благодаря чему копирование выражений дешевле, чем в плоском списковом — время создания копии пропорционально не длине записи, а количеству термов. t-переменные копируются за константное время. Но, с другой стороны, иногда бывает неочевидно, когда выражения копируются, а когда переносятся.
На данный момент есть реализация Рефала-6 только для Windows, на unix-like переносить её, вроде, не пробовали (Аркадий Климов поправит).
Тоже полукомпилятор: компилирует в промежуточный код (в виде сериализованных данных в текстовой форме), который затем выполняется интерпретатором. Написан на себе. Когда-то запускал Рефал-5 и Рефал-6 на 486 машине, первый выполнялся мгновенно, второй с заметной задержкой.
Интерпретатор динамичный — в процессе работы может загружать и выгружать модули, можно на лету править код функций (даже отладчик, вроде, написан на Рефале).
Есть библиотека встроенных мутабельных типов данных: динамические ящики, вектора, битовые вектора (надо смотреть в документации, уже забываю). Все они имеют общий объектно-ориентированный интерфейс. Вообще, библиотека у него богатая.
Реализация «запечатана» как и Рефал-5 — пользователь ограничен набором встроенных функций, реализованных в интерпретаторе. Однако, исходники доступны и при необходимости можно написать свои встроенные функции.
Рефал-Java
Диалект Рефала-6 (диалект диалекта). Написан братьями Климовыми (кто-то из них недавно писал, что большую часть кода написал Аркадий).
Синтаксис такой же, как в Рефале-6, имеет только некоторые расширения для совместимости с Java, например, ключевое слово $import, кажется. Компилируется в Java. Представление объектных выражений — массивное.
Имеет удивительно гладкий и чистый интерфейс с языком Java — объектные выражения представляются массивами Object’ов, если элемент массива — массив Object’ов — то это скобочный терм. Любое другое значение — символ. Функция Рефала компилируется в метод на Java, принимающий и возвращающий массив. Возвращаемое значение null символизирует неуспех.
Рефал-7
Придуман Сергеем Скоробогатовым, наследует от Рефала-5/Рефала-6. О нём мало кто знает, поэтому всё-таки дам ссылку (тем более, что ссылку эту найти непросто):
https://mazdaywik.github.io/direct-link/refal.pdf
Важное нововведение языка — функции высших порядков (вложенные функции), которые могут быть и безымянными (как в Рефале-5λ), так и именованными. Синтаксис из Рефала-6 наследует понятие действия, поддерживает неуспехи, но средства работы с ними беднее. И образцовые, и результатные блоки выкинуты из языка. Результатные выкинуты безвозвратно, образцовые блоки заменяются действием-вызовом функции:
R -> Rt
R => Rt
Здесь Rt — некий результатный терм. Первый вариант прозрачен для неуспехов, второй — нет. Семантику можно описать так:
R -> Rt ≡ R : e.1, Rt : t.2, <t.2 e.1>
R => Rt ≡ R : e.1 = Rt : t.2 = <t.2 e.1>
В качестве Rt предлагается использовать вложенную функцию, которая является результатным термом:
R -> { P1 = R1; P2 = R2; … }
что делает конструкцию похожей на блок Рефала-5.
Публично доступных реализаций Рефала-7 нет, было несколько реализаций, сделанных совместно со студентами-дипломниками. Но они похоронены на жёстком диске Скоробогатова.
Промежуточное представление данных — векторно-списковое представление — представление с отложенной конкатенацией. О нём, к сожалению, публично доступных материалов тоже нет.
Рефал-5λ
До себя добрался. Когда-то я, дабы самому понять компиляцию Рефала в императивный код, написал самоприменимый компилятор Рефала с синтаксисом, похожим на Рефал-5. Назвал его Простым Рефалом, поскольку оно действительно был минималистичен (хоть и крив). Этот компилятор порождал исходники на Си++, которые затем компилировались плюсовым компилятором в исполнимые модули. Потом я стал добавлять в него разные возможности, одной из первых были вложенные функции (но только безымянные) из Рефала-7.
Дальше Простой Рефал уже развивался на кафедре — разные фичи (преимущественно, оптимизации) добавляли студенты на курсовых и дипломах. Так в языке появились сначала присванивания (безоткатные условия), а потом уже и нормальные условия. В реализации добавился интерпретируемый код (который отличается от кода Романенко, в худшую сторону).
Потом я подумал, что ещё один несовместимый диалект Рефала никому не нужен и я решил его сделать совместимым с Рефалом-5. Добавил ещё один front-end и переделал библиотеку встроенных функций. Так появился Рефал-5λ.
На текущий момент Рефал-5λ — это точное надмножество Рефала-5 (почти точное, нет поддержки метафункций), в котором есть безоткатные присваивания (добавленные из соображений производительности), вложенные функции, нативные вставки (возможность записать тело функции на Си++), статические ящики и некоторые другие возможности (например, $INCLUDE). Реализация умеет компилировать в файлы интерпретируемого кода, в Си++, умеет несколько оптимизаций, работает на Windows, Linux и macOS, порождает исполнимые файлы. Может компилировать в файлы с интерпретируемым кодом, которые затем можно загрузить динамически (как .dll/.so). Компиляция в .dll/.so операционной системы пока не реализована. Надеюсь, сделаю следующим летом.
Несмотря на оптимизации и компиляцию в Си++, Рефал-5λ оказывается медленнее, чем обычный Рефал-5 (мерял). То ли из-за того, что сами встроенные функции (включая длинную арифметику) написаны на Рефале, то ли из-за неудачного промежуточного кода.
Нормального руководства по языку пока нет и я не знаю, когда его напишу. Поскольку к нему приложили руку много студентов, компилятор распространяется под копирайтом кафедры.
Про два других своих проекта — Модульный Рефал и Рефал-05 — я тут писать уже не буду. И так тут много написано.
Ещё в двух словах. Маратом Исламовым разрабатывался D-Refal — диалект Рефала, наследующий от Рефала-5, но при этом допускающий спецификаторы переменных. Причём для спецификаторов предусматривалась возможность задать чуть ли не грамматику. К сожалению, компилятор и язык не был доведён до конца. В ИПС РАН когда-то разрабатывался язык FLAC, ориентированный на алгебраические выкладки. По сути он тоже является диалектом Рефала, его реализация напоминает Рефал-6. О FLAC’е написано в одном из томов «Сборника трудов про функциональный язык Рефал» под редакцией Андрея Немытых. Вроде всё.
Если я не упомянул какой-то диалект или реализацию, значит, я о них забыл или не знал. Можете меня спросить о них, что-нибудь о них напишу.
А кто дочитал — молодец!
С уважением,
Александр Коновалов
From: Александр Коновалов a.v.konovalov87_AT_mail.ru <refal@botik.ru>
Sent: Thursday, February 14, 2019 11:57 AM
To: refal@botik.ru
Subject: Сравнение веток Рефала
Добрый день, Александр!
К сожалению, обзора разных диалектов Рефала я нигде не встречал. Диалекты и реализации Рефала не совсем корректно называть «ветками» или «версиями», они разрабатывались независимо, общей кодовой базы, на сколько я знаю, не имеют, имеют разный синтаксис, построены на разных принципах и идеологиях (особенно, Рефал Плюс).
Сам я его могу написать, но, наверное, не сегодня. И, если напишу, то он будет неизбежно субъективным. Но обсудить будет весело.
В выходные тогда напишу, если никто не напишет раньше меня.
С уважением,
Александр Коновалов
From: Александр Гусев gusev_aleksandr_AT_mail.ru <re...@botik.ru>
Sent: Thursday, February 14, 2019 9:59 AM
To: ref...@botik.ru
Subject: Re[4]: Немного статистики
Спасибо, Аркадий!
А существует где-то краткая информация по сравнению веток рефала? Статья, может быть какая-то.
А то есть рефал-2, рефапл-5, рефал-6 и рефал-плюс - это только те, что поименованы.
У каждой версии свои сторонники и блюстители. Или всё-таки придётся в каждую вникать?
Среда, 13 февраля 2019, 20:41 +03:00 от Arkady Klimov arkady.klimov_AT_gmail.com <re...@botik.ru>:
Здравствуйте, Александр!
Прошу прощения за некоторую задержку, пришлось немного повозиться, приводя в порядок версию дистрибуции. В принципе, есть все на сайте refal.net, но сильно старое, с тех пор довольно много было правок. Вот та страничка:
Документацию (описание языка) смотрите там, в ней ничего нового.
А дистрибутив пока у меня в дропбоксе возьмите:
Как и раньше, инструкция в help/readme.txt.
Главное - распакуйте в папку ...ref6, пропишите ее в PATH и откорректируйте путь в ri.bat соответственно.
Затем вызовите test/hello.bat.
В ближайшее время надеюсь переправить его на сайт, а также обновлю архивы исходников там.
Рефал-часть почти не изменилась с тех пор, а вот С-часть обновилась существенно.
Спрашивайте, не стесняйтесь, если будут проблемы.
С уважением,
Аркадий Климов
пт, 8 февр. 2019 г. в 23:43, Александр Гусев gusev_aleksandr_AT_mail.ru <re...@botik.ru>:
Аркадий, Спасибо за ответ!
Да, я читал переписку, не до самых глубин, конечно.
Пока прошу актуальную ссылку на Рефал-6 - почитать и хоть что-то попробовать, если возможно. Вроде Hello, world на трёх языках.
То, что я имел ввиду о музыке, это тоже формульные вычисления, конечно.Возможно, но наверно уже на "символьном уровне", до которого еще надо входной сигнал поднять.
С уважением,
Александр Гусев
gusev_a...@mail.ru
С уважением,
Александр Гусев
gusev_a...@mail.ru
С уважением,
Александр Гусев
gusev_a...@mail.ru
Доброе утро, Леонид!
«Александр, увидел только сейчас Ваше письмо.»
Я написал его только в полночь. Так что увидели Вы его спустя менее чем 4 часа после отправки, т.е. практически сразу. Или речь идёт о письме, написанном 20.02.2019, которое легло в основу статьи?
«Удивляет Ваша предвзятость в оценке новых версий Рефала и занижение работ по Рефалу-2 и его приложений.»
Согласен, внимание Вашей с Николаем Мансуровым реализации уделено очень мало.
Я подробно рассматривал те реализации, которые сам достаточно глубоко изучал. Или изучал саму реализацию, или документацию по ней, с осмыслением идей, положенных в основу языка. По Вашей реализации Рефала-2 я изучал только один препринт об односвязанных списках, т.к. он был на домашней страничке Сергея Романенко. Больше ничего о реализации я не знаю: компилирует она в машкод, язык сборки или другой ЯП (например, в Си), какие архитектуры и какие ОС поддерживает, на чём сама написана, как синтаксически выглядят расширения MPI и т.д. Поэтому в письме 2 года назад я о ней ничего не написал.
Статью я делал в спешке из письма, поэтому правки фактически свелись к замене первого лица («я думаю…») на третье («по мнению автора статьи…») и к простановке ссылок на то, что там было упомянуто. Действительно, нужно было поискать Ваши публикации на тему как военно-космических реализаций Фортрана, так и более свежих Ваших статей (упомянутые Вами статьи в «Вопросах кибербезопасности»). Можно было написать, что хоть эта реализация в сети недоступна, но у неё есть серьёзные промышленные применения. Это недоработка статьи.
Рассмотрение представлений данных во время выполнения не было целью статьи (как и исходного письма), поэтому односвязанные списки с кольцевыми цепочками там только упомянуты, но не расписаны подробно.
В статье я упомянул, что на Рефале-5 был написаны суперкомпиляторы SCP3 и SCP4. Но я об этом написал только из-за того, что в Рефале-5 есть любопытная функция Ev-met, написанная специально для ускорения SCP3, но в SCP4 она не используется. Т.е., если бы в Рефале-5 функции Ev-met не было, то не были бы упомянуты SCP3 и SCP4.
Нужно было подробнее написать во введении, почему одни реализации Рефала рассмотрены очень детально, а другие там только упомянуты. Это тоже недоработка статьи.
Желаю крепкого здоровья!
С уважением,
Александр Коновалов
From: Eisymont Leonid verger-lk_AT_yandex.ru [mailto:re...@botik.ru]
Sent: Friday, December 11, 2020 3:46 AM
To: re...@botik.ru
Subject: Re: Сравнение веток Рефала
Александр, увидел только сейчас Ваше письмо. Я очень тяжело болел, был месяц в больнице, сейчас на карантине, всего пока 2 дня.
Леонид!
Наверное, стоит эту статью полностью с нуля переписать и опубликовать в более серьёзном журнале (почитайте статью, которая следует сразу за моей 😁🤦♂️).
Нынешняя статья очень субъективна — всё-таки в основе лежит неформальное письмо для рассылки. И у того письма исходно была довольно конкретная цель: познакомить Александра Гусева с различными доступными реализациями Рефала. И все разобранные реализации (кроме Рефала-7) доступны в сети, к ним есть документация, их можно скачать и запустить. Про Рефал-7 я тогда написал, поскольку он является важным этапом в эволюции Рефала — предлагает полноценные функции высших порядков, чего ранее в Рефале не было.
У обсуждаемой статьи была другая конкретная цель — в короткие сроки сделать публикацию для отчётности 😁. А поскольку у меня уже была неплохая заготовка (при всех его недостатках всё-таки неплохой обзор получился), то я решил сделать из письма статью.
Если ещё одна реализация Рефала будет доступна в интернете — это будет здорово! Я раньше думал, что реализация Эйсымонта-Мансурова-Фролова это вообще что-то для служебного пользования. Используется где-то в НИЦЕВТе и прочих почтовых ящиках, лежит там под грифом коммерческой тайны и т.д.
Пятница, 11 декабря 2020, 10:04 +03:00 от Александр Коновалов a.v.konovalov87_AT_mail.ru <re...@botik.ru>:
Леонид!
Наверное, стоит эту статью полностью с нуля переписать и опубликовать в более серьёзном журнале (почитайте статью, которая следует сразу за моей 😁🤦♂️).
……………………………………
Леонид!
«Наработки для статьи у меня есть.»
Можно подробнее, о чём идёт речь? О сравнении веток Рефала с Вашей точки зрения или о Вашей реализации?
Мне было бы интересно описать эволюцию синтаксиса и семантики в Рефале: какие новые идеи вносит каждая реализация.
Рефал Турчина, описанный в 5 препринтах имел т.н. рекурсивные переменные — сопоставление с переменной осуществляло вызов функции.
Рефал-2 вносил могучие спецификаторы переменных, на сколько мне известно. Т.е. более общее, сложное и медленное в реализации решение (рекурсивные переменные) заменили более эффективным решением для частного случая — синтаксисом спецификаторов.
Рефал-4 — расширение базисного Рефала с выразимостью прогонки. (Сейчас, когда я обдумываю расширения древесных оптимизаций в Рефале-5λ, понимаю, что без понятий Рефала-4 получается слишком много костылей.)
Рефал-5 — более современный «Си-подобный» синтаксис с фигурными скобками, точками с запятой и длинными индексами переменных + небольшие удобства в виде условий и блоков. Условия можно рассматривать как некоторую замену и рекурсивных переменных, и спецификаторов.
Рефал Плюс = семантика Рефала-4 + синтаксис Рефала-5 + массивное представление. Последнее потребовало синтаксических костылей — форматов функций. Начиная с Рефала Плюс все последующие реализации (кроме Рефала-5λ) поддерживают неуспехи. Я сам к неуспехам критически отношусь.
Рефал-6 — упрощение и обобщение идей, заложенных в Рефале Плюс. Кроме того, реализация использует подвешенные скобки.
Рефал-7 — первый диалект, поддерживающий вложенные функции. Синтаксис наследует понятие действия от Рефала-6. Блоки как управляющая конструкция, исключены из языка, вместо них весьма оригинально используется действие вызова функции + вложенные функции.
Рефал-5λ — точное надмножество Рефала-5 со спорными синтаксическими расширениями.
Интересная попытка расширить Рефал была у Марата Исламова под руководством Н.Н. Непейводы. В язык были возвращены в некотором смысле спецификаторы Рефала-2, но в расширенной и углу́бленной форме — можно задавать вообще контекстно-свободные грамматики.
Некий Владимир Гошев (по всей видимости, аспирант) разрабатывает Рефал-5е, о чём сделал несколько публикаций. В статьи у него какие-то сумбурные, глубоко не вчитывался. Одна из статей напоминает записку к курсовой по компиляторам — подробно описывает лексический и синтаксический анализ, хотя это ИМХО не требующая внимания рутина. Диалект ни с чем не совместимый, исходников в интернете нет. Сам автор есть на GitHub, можно ему написать. Есть у него и вложенные функции, и неуспехи. Новых интересных синтаксических и семантических идей вроде нет.
Максим Кривчиков написал статью для журнала «Программирование», где описывает свою, пока безымянную, реализацию Рефала. Выступал на семинаре в ИПМ. Есть ли у него неуспехи — не помню. Максим планирует существенно переработать синтаксис, приблизив его к популярным функциональным языкам. Например, уже у него условие записывается задом-наперёд и с ключевым словом let.
Ещё я встречал на SourceForge реализацию Рефала, где вызов функции пишется не <F …>, а F<…>. Не изучал, ничего написать про неё не могу. Ещё есть какая-то реализация Рефал-0, написанная на Обероне, тоже не смотрел.
Но я пока не готов писать такую статью — нужно освоить программирование на Рефале Плюс с использованием рекомендуемого для него стиля. Без серьёзной практики анализ синтаксиса и семантики со стороны теории будет неточным.
Доброе утро, Александр!
«Я готов предоставить информацию, только не знаю, в какой форме это лучше сделать.»
Выложите на GitHub с длиннющим README.md, или напишите длинное письмо сюда.
«Основная проблема в том, что я занимаюсь этим по-прежнему один.»
Аналогичная проблема. У меня, правда, есть возможность привлекать студентов в добровольно-принудительном порядке. Студенты нехотя, но идут. Иногда за студентами приходится переписывать, т.к. у них мало опыта в программировании на Рефале и код получается неоптимальным.
С уважением,
Александр Коновалов
Леонид!
Если понадобится, наша кафедра может обеспечить Вам студентов на летнюю практику. Студенты у нас умеют программировать на нескольких языках и быстро осваивать новые. У нас вообще способные ребята. Сам порой думаю: кто кого здесь учить должен, я их или они меня.
С уважением,
Александр Коновалов
From: Eisymont Leonid verger-lk_AT_yandex.ru [mailto:re...@botik.ru]
Sent: Friday, December 11, 2020 11:08 AM
To: Александр Гусев <gusev_a...@mail.ru>; re...@botik.ru
Cc: fro...@nicevt.ru
Subject: Re: Сравнение веток Рефала
Про эту реализацию что-то не знаю. Упустил. Интересно, вкратце, понять. Что почитать?
Пятница, 11 декабря 2020, 11:08 +03:00 от Eisymont Leonid verger-lk_AT_yandex.ru <re...@botik.ru>:
Леонид!
«Александр, я сейчас другим занимаюсь, давайте дискуссию отложим, мешает.»
Давайте. Напишите тогда, когда освободитесь и сможете продолжить обсуждение.
Замечательно! Ближе к лету обсудим тогда.