Предисловие
На крайней (на дату написания) лекции Алексея Недори он высказал мысль, что он считает что если на вашем нечто можно написать факториал - это язык программирования. Что же... я теперь могу считать что у меня есть ещё один язык программирования!
Но прежде чем выпендриваться давайте я про него немного расскажу.
P.S. Если вам не интересно слушать мои мысли про советские ЯП то переходите к главе "Рапира". Что это?
Языковая археология
Существует прекрасный цикл презентаций от Петра Советова, который называется "Автоматизация программирования в СССР". Материал раскрывает крайне интересную тему развития и забытых идей в области компиляторов и трансляторов в СССР, вопреки моему (наивному) предварительному ощущению - многие из тех техник и подходов что были описаны оказались либо мне не знакомыми, либо смотрели на привычные алгоритмы с другого взгляда, но ближе к бизнесу.
К сожалению мы опрометчиво выкинули (по большей части) историю разработок в языках программирования в нашей стране через левое плечо. Но ведь языки программирования, как и любые проекты, возникают только если строить на плечах гигантов - прошлых проектов, а плечи наших соотечественников нам то гораздо ближе. Развитие идей падших, ну или ещё не падших но прошедших испытание временем, языков программирования позволило создать те языки которыми мы с вами и пользуемся.
Однако такое развитие не происходит в вакууме, для возникновения того или иного языка в неком определённом его виде должны быть ограничители и потребности оных - специальное железо, социальная/политическая потребность, открытия и идеи локальных университетов и лабораторий. Безусловно никто не мешает основываться на открытиях и идеях "мейнстрим" ЯП, все из которых не являются нашими разработками, более того вы должны это делать, однако в этом процессе абсолютно забывается локальная мысль, идея, история, которая на самом деле может сильно повлиять на те самые запросы и потребности и дать очень свежие и необычные мысли для создания ЯП.
По моему мнению необходимо возрождать и модернизировать те идеи и проекты, которые были сделаны до нас, продолжать нить идей.
Сказав всё это, хочется добавить, что пусть этим занимаются конечно умные люди - профессионалы своего дела, которых нам не занимать. Я в эту кагорту людей не вхожу, но идея есть идея, почему бы и не попробовать?
"Рапира". Что это?
Наконец-то давайте про язык. Был значит вот такой вот язычок - "Рапира". Довольно простенкий, с русским синтаксисом, использовался, как это и полагается, для обучения программированию.
Посмотрим на первую версию языка:
ПРОЦ СЧАСТЬЕ; (****************************************) (* Расчет количества счастливых билетов *) (****************************************) ИМЕНА: КОЛ_СУММ, I, J, К, КОЛИЧЕСТВО ; ФКОРТ (28,0) -> КОЛ_СУММ ; ДЛЯ I ОТ 0 ДО 9 :: ДЛЯ J ОТ 0 ДО 9 :: ДЛЯ К ОТ 0 ДО 9 :: КОЛ_СУММ [I+J+К+1] + 1 -> КОЛ_СУММ [I+J+К+1] ВСЕ ВСЕ ВСЕ; 0 -> КОЛИЧЕСТВО; ДЛЯ I ОТ 1 ДО 28 :: КОЛИЧЕСТВО + КОЛ_СУММ [I] ** 2 -> КОЛИЧЕСТВО ВСЕ; ВЫВОД: "Всего есть",КОЛИЧЕСТВО," счастливых билетов" КНЦ (* процедуры СЧАСТЬЕ *);
И тут у вас наверняка что-то сжалось внутри, да... сейчас с высоты наших растов и питонов это кажется несколько смешным. Но не спешите уходить! У меня есть для вас и другая версия языка, из брошюры, которая описывала обновлённую версию языка:
проц ШИВОРОТ_НАВЫВОРОТ () \▪ печать текста наоборот вывод: "Введите текст" \▪ приглашение ко вводу ввод текста: ТЕКСТ \ запрос текста в диалоге НАОБОРОТ:= "" \ пустой текст для К до #ТЕКСТ цикл \ от 1 НАОБОРОТ:= ТЕКСТ[К] + НАОБОРОТ \ #"огурец" = 6 кц \ "огурец"[3] = "у" вывод: НАОБОРОТ \ вывод результата на экран конец вызов ШИВОРОТ_НАВЫВОРОТ() ◆ Введите текст огурец ◆ церуго
Уже полегчало? Должно было! Ну по крайней мере мы выдыхаем, видя что присваивание это :=. Да, тут вы скажете что "ну дак мы этот Паскаль уже проходили старичок, это уже старьё". Не спорю и даже согласен, но посмотрите на это так: у языка уже есть несколько "версий" - так давайте сделаем ещё одну?
Вот этим я и собирался заниматься
Кратко - что есть максимально интересного в языке:
Динамическая типизация
Срезы (a.k.a slice, см. Zig/Rust/...)
Очень простой базис языка, к которому всё сводится
Динамический скоупинг
In/Out параметры
Предлагаю посмотреть на пару примеров и оценить самому:
Кортежи:
ДЕРЕВО := <* "вопрос", <* "да-ветка" *>, <* "нет-ветка" *> *> вывод: ДЕРЕВО[0] \ => вопрос вывод: ДЕРЕВО[1] \ => <* да-ветка *> вывод: ДЕРЕВО[1][0] \ => да-ветка
Срезы (вид на оригинальный кортеж или текст!)
проц ТЕКСТ_ПО_СЛОВАМ (ТЕКСТ) \▪ печать текста по словам ТЕКСТ:= ТЕКСТ + " " \▪ — это для обработки \ последнего слова пока ТЕКСТ /= "" цикл К:= индекс(" ", ТЕКСТ) \ номер первого вхождения \ " " в ТЕКСТ (или 0) если К /= 1 то вывод: ТЕКСТ[:К-1] \ "аб вг д"[:2] = "аб" все ТЕКСТ:= ТЕКСТ[К+1:] \ "аб вг д"[4:] = "вг д" кц \ "аб вг д"[4:5] = "вг" конец ТЕКСТ_ПО_СЛОВАМ ("Каждый коротышка был ростом с небольшой огурец") ◆ Каждый ◆ коротышка ◆ был ◆ ростом ◆ с ◆ небольшой ◆ огурец
"Рапира". Возрождаем
Итак, проект я разделил на две фазы:
Имплементация оригинального языка с возможными но минимальными изменениями
Модернизация языка с ожидаемым большим количеством изменений
Фаза 1
За референс взята уже упомянутая брошюра, задача сделать имплементацию компилятора для языка из брошюры. Почему не интерпретатор? Тут я позволил себе немного свободы выбора, вообщем-то интерпретатор я уже делал совсем недавно, к тому же это труднее чем кое-что другое - компиляция в Си. Тут мы потенциально получаем неплохую скорость, а также открываем двери к интеропу с Си.
Итак, момент выпендрежа:
функ ФАКТОРИАЛ (Н) если Н < 2 то возврат 1 иначе возврат Н * ФАКТОРИАЛ(Н - 1) все конец вывод: ФАКТОРИАЛ (5) \ => выводит 120
Теперь можно официально окрестить язык живым, я полагаю?
Одна из целей - это компилировать в читаемый Си код, судите конечно сами, вот вам пример во что компилируется программа выше (реальный вывод компилятора):
#include "runtime.h" #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // функ ФАКТОРИАЛ RAP_Object *RAP_FUNC_FAKTORIAL(struct RAP_CallFrame *_frame, RAP_Object **_args, unsigned int _argc) { RAP_Object *_local_N = _args[0]; RAP_Object *_t0 = RAP_create_int_obj(2); RAP_Object *_t1 = RAP_less_than(_local_N, _t0); if (_t1->logical_val) { RAP_Object *_t2 = RAP_create_int_obj(1); return _t2; } else { RAP_Parameter *_p0 = RAP_create_parameter(RAP_PARAMETER_MODE_IN, "Н"); RAP_Object *_t3 = RAP_create_callable_obj(_frame, &RAP_FUNC_FAKTORIAL, &_p0, 1); RAP_Object *_t4 = RAP_create_int_obj(1); RAP_Object *_t5 = RAP_subtract(_local_N, _t4); RAP_Object *_t6 = RAP_call_callable_obj(_t3, &_t5, 1); RAP_Object *_t7 = RAP_multiply(_local_N, _t6); return _t7; } } int main(void) { struct RAP_CallFrame _main_frame = {NULL, NULL, 0}; RAP_Parameter *_p1 = RAP_create_parameter(RAP_PARAMETER_MODE_IN, "Н"); RAP_Object *_t0 = RAP_create_callable_obj(&_main_frame, &RAP_FUNC_FAKTORIAL, &_p1, 1); RAP_Object *_t1 = RAP_create_int_obj(5); RAP_Object *_t2 = RAP_call_callable_obj(_t0, &_t1, 1); char *_s0 = RAP_stringify_object(_t2); printf("%s", _s0); printf("\n"); return 0; }
Думаю идея устройства runtime компилятора понятно из сниппета выше, и она довольно простая, всё - это объект:
typedef enum { RAP_OBJECT_TAG_NULL, RAP_OBJECT_TAG_LOGICAL, RAP_OBJECT_TAG_CALLABLE, // unifies proc and func RAP_OBJECT_TAG_INT, RAP_OBJECT_TAG_FLOAT, RAP_OBJECT_TAG_TEXT, RAP_OBJECT_TAG_TUPLE, RAP_OBJECT_TAG_SLICE, } RAP_ObjectTag; typedef struct { RAP_ObjectTag tag; union { bool logical_val; int64_t int_val; double float_val; struct RAP_Tuple *text_val; struct RAP_Tuple *tuple_val; struct RAP_Callable *callable_val; struct RAP_Slice *slice_val; }; } RAP_Object;
Если интересно узнать глубже приглашаю по ссылке в репозиторий см. Ссылки
Фаза 2
По большей части свои идеи я оставил на момент когда будет готова Фаза 1. Предварительно хочется конечно воспользоваться характером языка - динамическая типизация, простота синтаксиса.
Но важнее, что требуется решить следующие вопросы при модернизации:
Синтаксис - по личному мнению автора, для языка с кириллицей надо брать питоно-подобный синтаксис на отступах, чтобы не переключать раскладку и ставить скобочки, плюс это сохранит простоту синтаксиса
Таргет генерации кода - этот вопрос ставится и на первой фазе и принято решение на данном этапе генерировать код на языке Си, это позволит:
Упростить разработку
Иметь легко распространяемый генерируемый код
Заиметь потенциал к хорошей производительности языка, избежав преграды интерпретации
Открыть дверь к прямому взаимодействию с Си кодом, позволив использовать большое количество готовых библиотек
Отсутствие ООП/структур/именованых кортежей - в языке присутствуют нетипизированные контейнеры - кортежи, которые могут выступать как структуры, но так как именованных элементов нет - стоит задуматься о добавлении такого конструкта, а также об организации взаимодействия таких объектов, будь это ООП или что-то иное (наследование и т.п.)
Модульная система - в препринте мало сказано о модульной системе, стоит задуматься об организации оной
Система сборки и организации зависимостей - встроенная система сборки и работы с зависимостями позволит избежать участь соревнования различных таковых систем сделанных пользователями, можно посмотреть на истории этого всего в Python и проблемы миграции с одной системы на другую
ПИВИС/REPL - добавить возможность работы с языком в стиле: прочитать - исполнить - вычислить - и-снова, в стиле интерпретируемых языков
Управление памятью
ООП?
Позволю себе также написать несколько крайней сырых идей, которые у меня есть по поводу реализации ООП/системы сущностей/объектов/... в языке.
Итак, обратимся к брошюре, там мы видим вот такую интересную штуку:
### 1.6. Модули и устройства Планируемые возможности аппарата модулей и устройств: - подключение модуля пополняет список стандартных имен (в том числе имен стандартных процедур и функций); - подключение модуля пополняет набор простых предписаний (т.е. языковыми средствами создаются исполнители, аналогичные существующим в Робике [1]);
Подождите-ка, а что такое эти самые "исполнители"? В языке предшественнике нашей Рапире был вот такой интересный конструкт. Для разнообразия и чтобы вы прониклись эстетикой прикреплю на этот раз картинку:

Ничего не напоминает? А мне вот очень напоминает что-то типо акторов в Erlang, например. Пока я не буду раскачивать эту идею дальше, просто потому что сам знаю позорно мало про акторов, поэтому оставим на Фазу 2.
Послесловие
Не стоит думать что это какой-то слишком серьёзный проект - мотивация тут это желание изучить что-нибудь новое, проверить концепт возрождения. Так как автор не мастак в разработке ЯП, то относиться к коду/результату советую скептически.
Следите за обновлениями, когда-нибудь я доберусь до Фазы 2 и станет интересно!
Ссылки
Почитать про "Рапиру" можно в брошюре советского времени
Почитать про "Робик" можно тут
Мой личный блог, пост из которого послужил публикацией к этой статье
Комментарии (24)

Artik4
20.03.2026 14:56А был ещё и ЯП Алгол-60... И тоже на русском, изучал немного в начале 80х, в нём обычно первые три буквы команды писалось, типа ВЫВ вывод, ПЕЧ печать .и тд...

Anton_Timofeev
20.03.2026 14:56Переключать раскладку каждый раз, когда надо набрать "<" или ">"? Хорошо хоть фигурных скобок нет)
Нужна кириллическая клавиатура программиста, чтобы все любимые небуквы были отдельными клавишами, как на латинице.
medvedd
20.03.2026 14:56Когда-то на БЭСМ-6 был компилятор Альфа-6 — оптимизирующий компилятор слегка расширенного Алгол-60. Служебные слова все были русские, никаких там BEGIN и END, только НАЧАЛО и КОНЕЦ и т.п. Запускалось все с перфокарт, информация на которых кодировалась построчно. Таким образом на карту входило 120 символов (вместо 80).
Для Альфа-6 были сделаны специальные перфораторы. Кроме обычных клавиш, каждое служебное слово имело отдельную клавишу, и кодировалось это отдельным символом на перфокарте. Помню несколько таких перфораторов на ВЦ СО АН. К сожалению, фотографии найти не смог.

ermouth
20.03.2026 14:56вот очень напоминает что-то типо акторов в Erlang, например
Это вы загнули, конечно. Ничем вообще оно на erlang не похоже.

Siemargl
20.03.2026 14:56У старых языков есть критичная проблема - множество парадигм и просто приёмов возникли позже, с опытом развития технологий.
Те-же методы обработки ошибок или метапрограммирование например.
Даже элементарный параллелизм.

dacsson Автор
20.03.2026 14:56Согласен, поэтому есть и этап модернизация языка после имплементации оригиналы - там ожидается много изменений, которые будут ложиться на готовый строгий базис

purple_elephant
20.03.2026 14:56В 2007 на Хабре писали о русскоязычном ЯП Глагол на основе если не изменяет память Modula. Был концептуально интересный язык программирования советского периода Рефал. Вроде бы делали русскоязычный вариант системы Оберон. В конце концов - есть 1С и его язык как таковой тоже отдельно имплементирован. По моему, особенно интересного из Рапиры не получится. На фоне того что - уже делалось. Язык программирования же - это не только он сам, это экосистема вокруг, IDE, ИИ модели которые с этим работают. Это решение министерства образования о возможности использования на экзамене информатики.

lovejump
20.03.2026 14:56Отступы не есть абстрактный программный тип, который может быть осмысленен на языковом уровне. Они даже не видны. Это глубочайшее заблуждение. Питонисты это извращенцы. Настоящие. Закоренелые. Когда то это им боком выйдет..

dacsson Автор
20.03.2026 14:56Как это не видны? Отступы прекрасно видны в любом редакторе

AndreyDmitriev
20.03.2026 14:56Ну как видны, я вот использую Питон очень "эпизодически", от случая к случаю минимально правя чужие скрипты и время от времени мне таки прилетает граблями по лбу в виде:
^ TabError: inconsistent use of tabs and spaces in indentationХотя я и в курсе этой "фишки"...
maisvendoo
Прикиньте - в СССР и люди жили. И ели, и пили и спали. И даже ходили в туалет
dacsson Автор
бред какой-то.
maisvendoo
Я к тому, что да, были. И что тут удивительного и особенного?
P. S.: Выше был сарказм
Moog_Prodigy
Были и после СССР, ну например и я писал подобное. Но чисто в рамках "по приколу". И не один я, тысячи людей энтузиастов создавали свои ЯП. В основном тоже по приколу.
Русский язык очень не подходит для программирования. Даже не потому, что коряво выглядит, а потому что при всей его сложности мы его видим как простым. В реальности условие "if" или ЕСЛИ можно в условной бейсикоподобной программе нормально воспринять, то а почему бы не ввести "если, но вдруг" (if not or if true - совершенно мозговыносящая конструкция), "авось" (if(RND==True) > 0) или "да пошло все оно" (RND).
Мы так не привыкли с нашим языком так обращаться и понимать его. Он очень емкий и предназначен для людей а не для машин.
К слову, где то на реддите читал про сугубо китайский ЯП. И были комменты со ссылками на более старые проекты, что говорило о том, что и китайцы баловались с этим. И у них та же самая байда что и у нас. Вот а нафига? Если в английском максимально упрощено "моя зовется Главный Человек, моя код писать проект, а по выходным я люблю посмотреть на ногомяч" - то и машинам это проще формализовать, как бы коряво по нашим меркам это не выглядело. А оно выглядит весьма коряво, просто потому что проще.
Конечно можно сделать ЯП и на Ложбане, кто мешает?
dacsson Автор
Точно также может и какой-нибудь John Smith в свой язык добавить "if ..., but in any chance", "perhaps", "fuck it" - идею не очень поймал
А английский предназначен для машин, создавался для этого?
Машина будет "формализовать" чтобы это не значило ту грамматику, обработку для который вы придумаете, никто не собирается парсить/исполнять/... весь русский язык - а какие уж буковки в этой грамматике компьютеру по больше части пофиг с точки зрения какой-то сложности "формализации".
Это мы так, переводя, привыкли думать об английском, пологаю что американец/англичанин явно не думает в таких понятиях об английском
dacsson Автор
Это было обращение к тем, кто не был знаком как раз таки с историей ЯП в СССР, а не знакомых с ней довольно много
P.S.: Выше тоже был сарказм
Dimotik
Чё ты, тупой дятел, сумничать решил
maisvendoo
Фу как грубо! Вас мама не учила не хамить, нет?