flang: язык, которому сутки
Этот трек описывает язык, который на момент написания существовал примерно
сутки. Репозиторий digitable-lol/flang
создан 3 августа 2026 года в 21:07 UTC; статьи сверены по состоянию на коммит
9164aa3 от 4 августа, 00:54 UTC. К этому моменту в репозитории было 32
коммита, а flang version отвечал 0.1.0.
Первая редакция трека была написана по коммиту ec89e78 — на час раньше. За
этот час у языка появились два новых бэкенда кодогенерации и переписался
парсер ядра, так что часть текста пришлось править ещё до публикации. Это не
курьёз, а точная иллюстрация того, о чём трек: срез, а не описание языка.
Ни одна конструкция ниже не является обещанием. Язык в версии 0.x, и в
разделе Status файла README.md записано, что компатибельными поверхностями
считаются только канонический JSON и коды диагностик, а «синтаксис растёт через
документированные предложения». Синтаксис будет меняться, часть описанных
ограничений исчезнет, часть решений развернётся в обратную сторону.
Компенсируется это одним приёмом, который в треке соблюдается везде: всё
проверено запуском. Каждый фрагмент кода — либо дословная выдержка из файла
репозитория с указанием пути, либо программа, которую мы написали, прогнали
через flang check и flang test и показываем вместе с ответом инструмента.
Там, где что-то не работает, мы пишем «не работает» и приводим диагностику,
а не обходим молчанием.
Что это за язык
flang — язык с отступным синтаксисом без скобок, русской и английской поверхностями, суммами типов, списками, строками-как-данными, рекурсией и сопоставлением с образцом. Функции в нём не являются значениями первого класса. Программа — набор функций и объявлений типов; вычисление функции — чистое отображение аргументов в результат, без состояния, ввода-вывода и исключений.
Вот полностью рабочая программа — файл flang/stdlib/lists.flang, первые
строки после заголовка модуля:
тотальная функция «Длина»
принимает элементы: список числа
возвращает число
пример «Пустой список»
дано элементы равно пустой список
ожидается 0
пример «Три элемента»
дано элементы равно [7, 8, 9]
ожидается 3
разбор элементов
случай пусто
то 0
случай голова и хвост
то 1 плюс «Длина» от хвоста
Здесь видно почти всё, что делает язык узнаваемым. Отступы вместо скобок. Имена
в ёлочках, потому что имя — это фраза, а не идентификатор. Примеры лежат внутри
функции, а не в отдельном тестовом файле. И слово тотальная, которое и есть
главное решение языка.
Два класса программ
Полнота по Тьюрингу и гарантия завершения несовместимы: либо язык умеет всё, либо про любую его программу можно доказать, что она остановится. Обычно язык выбирает одно. flang не выбирает, а делит программы на два класса, и класс проверяется компилятором.
Функция, помеченная тотальная, обязана доказать, что каждый её рекурсивный
вызов получает структурно меньший аргумент — хвост списка, поле варианта,
элемент коллекции. Не доказала — ошибка FLANG_NOT_TOTAL, и это ошибка сборки,
а не предупреждение. Функция без пометки может рекурсировать как угодно и
завершаться как получится.
Разница не косметическая. От класса зависит, можно ли программу напечатать в C, можно ли ей доверить встраиваемый факт-чекинг и завершатся ли её примеры-тесты. Подробно — в главах «Два класса программ» и «Тотальность».
Откуда он взялся
flang вырос из FTS — языка исполняемых спецификаций, которому в этом каталоге посвящён отдельный трек. Отношение между ними стоит понять сразу, потому что оно не то, которое подсказывает интуиция.
Репозиторий digitable-lol/flang назван по языку, но бо́льшая часть его
содержимого — это FTS. Сам flang лежит в подкаталоге flang/, а всё, что
находится в корне — src/, docs/, editors/, tools/, benchmarks/ — про
FTS. Различие в треке соблюдается строго: путать их значит приписывать
суточному языку зрелую инфраструктуру, которой у него нет.
Заметим, что и сам репозиторий это признаёт. README.md переписан от языка и
содержит раздел «How FTS and flang relate», а в нём — абзац «What is not
settled, stated plainly»: ядро FTS на TypeScript остаётся рабочей реализацией и
эталоном сверки, пакет по-прежнему называется @digitable/fts, и «репозиторий
назван по языку, которым становится, тогда как значительная часть его
содержимого — всё ещё инструментарий FTS».
Связь между языками при этом жёсткая и проверяемая: любая существующая
FTS-модель обязана быть валидной программой flang и давать тот же результат.
Это не пожелание, а тест. В README.md записано: проверено на 19 593 входах,
ноль расхождений. Разбору этой границы посвящена глава «flang и FTS».
Маршрут трека
| Статья | О чём |
|---|---|
| «flang и FTS» | Что от FTS, что своё, и где проходит граница |
| «Два класса программ» | Тотальная и обычная: главное решение языка |
| «Инструмент» | Инструмент: check, run, test, ast, emit, facts |
| «Синтаксис по факту» | Синтаксис по факту: модули, функции, выражения, образцы |
| «Система типов» | Система типов и то, чего в ней сознательно нет |
| «Тотальность» | Как доказывается завершение и что анализ отвергает |
| «Стандартная библиотека» | Стандартная библиотека и связывание модулей |
| «Интерпретатор» | Интерпретатор: явный стек, лимиты, хвостовые вызовы |
| «Кодогенерация» | Печать в C, Go, JavaScript, Rust и Python — с проверкой сборкой |
| «Ядро FTS на flang» | Ядро FTS, переписанное на flang |
| «Чего в языке пока нет» | Чего в языке пока нет — проверенный список |
| «Как читать репозиторий» | Как читать репозиторий и как участвовать |
Кому это может пригодиться
Честно: в продакшене — пока никому. Язык суточной давности без стабильного синтаксиса, без подсветки в редакторах, без пакетного менеджера и без пользователей за пределами репозитория. Если задача в том, чтобы завтра выкатить сервис, этот трек не о том.
Он полезен иначе. flang — редкий случай, когда язык можно прочитать целиком:
лексер, парсер, тайпчекер, анализ тотальности, интерпретатор и пять бэкендов
кодогенерации — это около четырнадцати тысяч строк JavaScript в flang/src/,
и они лежат в одном каталоге (вместе с CLI, стандартной библиотекой и ядром
FTS на самом flang — около двадцати тысяч; рантаймы бэкендов на C, Go, Rust и
Python и тесты сюда не входят).
Для того, кто проходил трек «Компиляторы и языки»
и хочет
увидеть не учебный пример, а работающую систему целиком, размер удачный: она
уже настоящая, но ещё обозримая.
Второе: решения в этом языке выбраны неочевидно и почти всегда объяснены прямо в исходниках — длинными комментариями, в которых написано, что рассматривалось и почему отвергнуто. Читать чужие обоснованные компромиссы полезнее, чем читать готовый результат.
Как читать этот трек
Начните с глав «flang и FTS» и «Два класса программ»: без них остальное разваливается на список конструкций. Дальше можно идти по порядку либо прыгнуть в интересующий слой — статьи про интерпретатор, кодогенерацию и тотальность самостоятельны.
Если собираетесь повторять — понадобится Node.js (в README.md заявлена версия
20 или новее; наши прогоны шли на 24.18.0) и клон репозитория. Ни npm install,
ни сборки для работы с .flang не нужно: CLI запускается прямо из исходников,
node flang/bin/flang.mjs check файл.flang. Подробности — в
главе «Инструмент».