flang — язык с доказуемым завершением Своя поверхность: как написать тот же язык по-французски
0%

Своя поверхность: как написать тот же язык по-французски

Своя поверхность: как написать тот же язык по-французски

Обычный язык программирования пишут по-английски, и это не решение, а привычка, которую никто не пересматривал. if, while, return — английские слова, и человек, для которого английский не родной, каждый день читает код на языке, на котором не думает.

flang устроен иначе: слова языка живут в таблице, а не в грамматике. Сегодня таблица знает четыре набора слов — русский, английский, эсперанто и китайский, — и все четыре равноправны: компилятор не спрашивает, на каком языке написан файл, он просто узнаёт слова.

Эта глава — про то, как это сделано и как добавить пятый.

Одна программа, три записи, одно дерево

В репозитории лежит факториал, записанный трижды: examples/rosetta/factorial.flang, examples/surfaces/factorial.eo.flang, examples/surfaces/factorial.zh.flang. Вот одна и та же функция на трёх поверхностях:

тотальная функция «Произведение»
  принимает элементы: список числа
  возвращает число
  пример «Произведение четырёх»
    дано элементы равно [1, 2, 3, 4]
    ожидается 24
  свёртка элементы начиная с 1 как акк и эл  акк умножить на эл
totala funkcio «Produto»
  akceptas eroj: listo de nombro
  redonas nombro
  ekzemplo «Produto de kvar»
    donite eroj egalas [1, 2, 3, 4]
    atendata 24
  faldo eroj komencante per 1 kiel akumulo kaj elem  akumulo fojoj elem
完全 函数 «乘积»
  接受 诸项:列表 数字
  返回 数字
  示例 «四数之积»
    给定 诸项 等于 [1,2,3,4]
    期望 24
  折叠 诸项 起始于 1 作为 累加 和 当项 → 累加 乘以 当项

Это не «перевод документации» и не три похожих файла. Проверяется утверждение так — командой, которую можно повторить:

$ flang check examples/rosetta/factorial.flang
$ flang check examples/surfaces/factorial.eo.flang
$ flang check examples/surfaces/factorial.zh.flang

Все три отвечают «проверено — разбор, типы, завершаемость, ядро и примеры; замечаний нет». А flang ast показывает, почему: деревья разбора совпадают по форме — пять функций, одинаковая структура узлов, одинаковые типы и примеры. Отличаются только имена, которые написал автор. Замер сделан на выпуске 0.7.3 сравнением вывода flang ast у всех трёх файлов.

Отсюда практическое следствие: программу, написанную по-китайски, читает и печатает в C тот же компилятор, что и русскую. Поверхность не влияет ни на доказательство завершения, ни на печать в целевые языки — она кончается на лексере.

Где живут слова

Таблица — в flang/self/lexer.flang, то есть в самом компиляторе, написанном на самом языке. Две формы записи, обе строками:

|тотальная:total|total:total|totala:total|完全:total|
|total@ru:тотальная|total@en:total|total@eo:totala|total@zh:完全|

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

Понятий в таблице 150 (счёт: все пары понятие@поверхность в flang/self/lexer.flang на 0.7.3). Открыты они так:

поверхность понятий
русская 150
английская 149
китайская 138
эсперанто 134

На всех четырёх открыто 133 понятия. У семнадцати слова где-то нет — и это не недоделка, а записанное решение.

Поверхность не обязана быть полной

Самый поучительный пример — эсперанто и слово модуль.

В эсперанто «modulo» называет и программный модуль, и остаток от деления. Второе значение в таблице уже занято: modulo отдано понятию «остаток от». Одно слово не вправе называть две конструкции — значит эсперантская поверхность здесь молчит, и файл factorial.eo.flang пишет заголовок английским словом module:

module «Faktorialo»

Автор примера объясняет это прямо в комментарии к файлу: «выбор термина принадлежит владельцу языка, а не переводчику».

Вот все семнадцать понятий, у которых на какой-то поверхности слова нет:

понятие по-русски нет на
alias это en, eo, zh
ensures обеспечивает eo, zh
requires требует eo, zh
forall для всех eo, zh
induction индукция по eo, zh
claim утверждаем eo, zh
qed следовательно доказано eo, zh
byExample, byHypothesis, byProperty по примеру, по предположению, по свойству eo, zh
decreases убывает eo, zh
module модуль eo
not не eo
nested вложен объект eo
embedding вложение eo
supervision надзор eo
opPercent процентов zh

Видно закономерность: не открыт прежде всего слой доказательств — на эсперанто и китайском ещё не выбраны слова для обеспечивает, требует, индукция по. Файл на такой поверхности пишет недостающее понятие словом другой поверхности, и компилятор это принимает: смешивать слова разрешено, потому что понятие одно.

Что придётся решить, а не перевести

Поверхность — это не словарь, и главная работа в ней не переводческая.

Слово должно быть одно на понятие. История с modulo — не исключение, а типичный случай: в любом естественном языке найдётся слово, которое хочет назвать две разные вещи. Решает это владелец языка, а не переводчик, и решение записывается в таблицу вместе с причиной.

Слово должно быть отделимо. У китайской поверхности пробелов внутри фразы нет, и это разбирается отдельным правилом: 函数长度 — одно имя, а 函数 长度 — два слова. Поэтому между ключевыми словами китайской поверхности пробел обязателен, ровно как между тотальная и функция. Полноширинные при этом делят поток наравне с обычными и значат то же самое.

Буквы должны быть известны лексеру. Надстрочные буквы эсперанто (Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ) стоят в таблице заглавных отдельными парами: без них Se в начале строки не свелось бы к se, и ключевое слово не нашлось бы. Для французского то же самое касается É È Ê À Ç Ô Û — их надо добавить в ту же таблицу, иначе Élément в начале строки не совпадёт с élément.

Как добавить французскую поверхность

Работа делится на четыре шага, и первый — не про код.

1. Выбрать слова. 150 понятий, из них хотя бы 133 — те, что открыты на всех поверхностях сегодня. Для каждого нужно французское слово, которое не занято другим понятием: fonction, accepte, retourne, exemple, étant donné, attendu, si, alors, sinon. Слова из нескольких слов допустимы — étant donné не хуже, чем русское вложен объект.

2. Дописать таблицу. Обе формы в flang/self/lexer.flang: прямую (fonction:function) и обратную (function@fr:fonction). Компилятор написан на самом языке, поэтому правка — это правка программы на flang, и она проходит те же проверки, что любая другая.

3. Добавить буквы. Диакритика французского — в таблицу заглавных, рядом с эсперантской.

4. Написать пример и сверить деревья. examples/surfaces/factorial.fr.flang, слово в слово с русским оригиналом. Доказательство, что поверхность вышла правильной, — не чтение, а сравнение:

$ flang check examples/surfaces/factorial.fr.flang
$ flang ast examples/surfaces/factorial.fr.flang > fr.json
$ flang ast examples/rosetta/factorial.flang     > ru.json
# деревья обязаны совпасть по форме: те же функции, узлы, типы и примеры

Если форма разошлась — где-то слово попало не на то понятие, и это видно сразу, а не через полгода на чужом коде.

Чего поверхность не даёт

Честная граница, чтобы не ждать лишнего.

Поверхность меняет слова языка, а не имена в вашей программе: «Рассчитать скидку» останется тем, что вы написали, и печать в целевой язык оставит его как есть. Она не переводит стандартную библиотеку: имена её функций — тоже написанные кем-то имена. И она не делает язык понятнее сама по себе — если правило запутано, оно будет запутанным на любом наборе слов.

Зато она снимает ровно одну вещь, которую обычно принимают как данность: чтобы писать проверяемые правила своей предметной области, не обязательно делать это словами чужого языка.

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов