Skip to content

Commit d5f830c

Browse files
Marat Zimnurovclaude
andcommitted
Библиотека на функциях-значениях написана — и не там, где должна
Пункт 5 плана: свёртка, отображение, фильтр, поиск, сортировка и композиция принимают функцию аргументом. 36 функций, все тотальные, 55 примеров, печать во все восемь целей, C под -Werror -pedantic, сверка с интерпретатором на 179 точках, сверка с девятью специализированными функциями lists.flang на 64. Положить её в flang/stdlib нельзя, и это проверено запуском, а не выведено из «печать заработала — значит можно». Тот же файл там роняет пять тестов: три в self-bootstrap и два в self-parser, с диагностикой flang₁ «FLANG_PARSE: не разобрана конструкция: ожидался тип». Печать во все восемь целей и разбор самоприменением — разные контракты; сняли первый, второй остался. Три из пяти упавших — ровно те, которыми за то же заплатил полиморфизм. Каталога для такого файла в репозитории тоже нет: hof-emit смотрит на flang/** целиком. Поэтому модуль лежит в flang/test/stdlib-hof.test.mjs — там же, где по той же причине живут исходники фаз 1 и 3, — и рядом стоит улика, которая покраснеет в день фазы 5 и потребует перенести его в flang/stdlib/higher-order.flang. Четыре объяснения недостачи пережили сами недостачи и заменены проверенными: «функции не являются значениями» (lists.flang), «передать предикат некому» (там же), «значение варианта в примере записать нельзя» (strings.flang — третье место, где это пережило починку), «типы не параметрические» (optional.flang и result.flang). Про язык всё это неправда; правда про репозиторий, и она уже. Каждое проверено прогоном. Там же исправлено «связывания между модулями нет» в каталоге LeetCode: импорт работает, flang test на import-check.flang даёт 46 сошедшихся примеров. В каталог недостач добавлена запись «функции первого класса в программах репозитория» с двойной уликой в missing.test.mjs: эталон обязан ПРИНЯТЬ программу с функцией-значением, а парсер на flang — ОТКАЗАТЬ. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P6ehGNnEcrkCK1V5iMHNYi
1 parent 24e3079 commit d5f830c

9 files changed

Lines changed: 1265 additions & 25 deletions

File tree

flang/PLAN.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,36 @@ gcc и clang, Java, Elixir, Rust, Python; Go и .NET на машине нет
178178
это две обычные функции и три обычные суммы; чего не хватает остальным семи,
179179
расписано таблицей в том же разделе контракта.
180180

181-
**5. Стандартная библиотека, настоящая.** Сейчас 76 функций, и они дублируются
182-
по типам. С (1) и (2) появляются свёртки, отображения и фильтры, работающие с
183-
любым типом и любой функцией; персистентные структуры; строки и числа одним
184-
набором.
181+
**5. Стандартная библиотека, настоящая. 🟡 Написана — но лежит не там, где
182+
должна.** Сейчас в `flang/stdlib` 76 функций, 69 из них тотальные, 151 пример.
183+
Дублирование посчитано, а не оценено: девять функций отличаются друг от друга
184+
ровно одним подставленным предикатом, сравнением или операцией — «Все не
185+
меньше» и «Любой не меньше», «Минимум» и «Максимум», «Сумма» и «Произведение»,
186+
«Вставить по порядку» и «Сортировать», «Сжать суммами»; ещё 55 функций из 202 в
187+
`stdlib`, `examples/leetcode` и `examples/rosetta` — побайтовые копии друг
188+
друга.
189+
190+
Замена написана целиком и проверена целиком: 36 функций, ВСЕ тотальные, 55
191+
примеров, печать во все восемь целей, C под `-Werror -pedantic`, сверка с
192+
интерпретатором на 179 точках (gcc, clang, JavaScript). Свёртка, отображение,
193+
фильтр, поиск, сортировка и композиция принимают функцию аргументом; отдельным
194+
тестом сверено, что общие функции дают ровно то же, что девять
195+
специализированных.
196+
197+
Положить её в `flang/stdlib` нельзя, и это измерено: тот же модуль там роняет
198+
ПЯТЬ тестов — три в `self-bootstrap` и два в `self-parser`, с диагностикой
199+
flang₁ `FLANG_PARSE: не разобрана конструкция: ожидался тип`. Печать во все
200+
восемь целей (пункт 2, фаза 3) этого не меняет: корпус сверки собирается по
201+
маске каталога, а `self/parser.flang` новой формы не знает. То же и с (1):
202+
параметрический тип, снимающий дублирование по типам, репозиторию тоже
203+
запрещён. Значит пункт 5 упирается не в (1) и (2), а в ИХ САМОПРИМЕНЕНИЕ —
204+
фазу 5 в `HOF.md` и фазу 4 в `POLY.md`.
205+
206+
Пока их нет, библиотека живёт в `flang/test/stdlib-hof.test.mjs` — там же, где
207+
по той же причине лежат исходники фаз 1 и 3, — и рядом с ней стоит улика,
208+
которая покраснеет в день, когда `self/` научится, и потребует перенести модуль
209+
в `flang/stdlib/higher-order.flang`. Осталось после этого: персистентные
210+
структуры и «строки и числа одним набором» — они требуют (1), а не (2).
185211

186212
**6. Отказоустойчивость.** Шаги 1–3 конкурентности сделаны, печать в Elixir в
187213
работе. После (4) процессы получают ввод-вывод, и система становится тем, чем

flang/cat/HOF.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,10 +546,43 @@ JavaScript. Go и .NET печатаются и проверяются струк
546546
парсер (AST-контракт сверяется побайтово с эталоном — расхождение видно сразу),
547547
затем типы.
548548
549-
**Фаза 6 — stdlib.** Только после фазы 5, ни минутой раньше:
550-
`flang/stdlib/*.flang` входит в тот же корпус, что и `examples`. Тогда
551-
появляются настоящие свёртки, отображения и фильтры, работающие с любой
552-
функцией, — то, ради чего пункт 5 плана ждёт этого пункта.
549+
**Фаза 6 — stdlib. 🟡 Библиотека НАПИСАНА, но перенести её нельзя до фазы 5.**
550+
551+
Модуль «Высший порядок» — 36 функций, все тотальные, 55 примеров — лежит в
552+
`flang/test/stdlib-hof.test.mjs` и проверен целиком: типы, завершаемость,
553+
примеры, `flang check` и `flang test` через настоящий CLI, печать во все восемь
554+
целей, сборка C под `-Werror -pedantic`, сверка с интерпретатором на 179 точках
555+
(gcc, clang, JavaScript), плюс сверка с девятью специализированными функциями
556+
`stdlib/lists.flang` на 64 точках — они дают ровно то же.
557+
558+
Соблазн был положить его сразу в `flang/stdlib/`: фаза 3 сделана, печать
559+
работает. Проверка запуском это опровергла — тот же файл там роняет ПЯТЬ
560+
тестов:
561+
562+
```
563+
flang/stdlib/…: связывание на flang дало диагностики
564+
FLANG_PARSE не разобрана конструкция: ожидался тип (self-bootstrap)
565+
flang/stdlib/…: связанный AST разошёлся (self-bootstrap)
566+
flang/stdlib/…: диагностики разошлись (self-bootstrap)
567+
flang/stdlib/…: парсер на flang отказал там, где образец разобрал (self-parser ×2)
568+
```
569+
570+
Три из них — ровно те, которыми за то же самое заплатил полиморфизм
571+
(`POLY.md`); два — те, до которых он не дошёл. Урок тот же и стоит записи
572+
третий раз: **печать во все восемь целей и разбор самоприменением — РАЗНЫЕ
573+
контракты**, и снятие первого не снимает второго.
574+
575+
Каталога, куда такой файл можно положить, в репозитории тоже нет:
576+
`hof-emit.test.mjs` требует от каждого `.flang` под `flang/`, чтобы проход
577+
дефункционализации вернул ТОТ ЖЕ объект, — а библиотеку он по существу
578+
переписывает.
579+
580+
Чтобы объяснение не пережило недостачу (это уже случалось четырежды за сутки),
581+
рядом с модулем стоит улика: тест «`self/parser.flang` не понимает библиотеку».
582+
В день, когда фаза 5 будет сделана, он покраснеет и потребует перенести модуль
583+
в `flang/stdlib/higher-order.flang`. Вторая улика, на ту же недостачу со
584+
стороны каталога языка, — в `flang/test/missing.test.mjs`: эталон обязан
585+
ПРИНЯТЬ программу с функцией-значением, а парсер на flang — ОТКАЗАТЬ.
553586
554587
**Чего решено не делать никогда.** Замыканий над локальными именами: тег с
555588
захватом — это фаза 4, а анонимная функция, замыкающая произвольное окружение,

flang/examples/leetcode/index.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"версия": 1,
33
"язык": "flang",
44
"каталог": "flang/examples/leetcode",
5-
"описание": "Решения задач LeetCode на flang. Каждый файл самодостаточен: связывания между модулями в языке нет, поэтому вспомогательные функции повторяются в каждом решении.",
5+
"описание": "Решения задач LeetCode на flang. Каждый файл самодостаточен НАРОЧНО, а не по нужде: здесь стояло «связывания между модулями в языке нет», и это неправда — «использует «Списки» из \"../stdlib/lists.flang\"» работает, проверено запуском flang check и flang test на flang/examples/import-check.flang (46 примеров, все сходятся). Самодостаточность оставлена потому, что решение задачи читается целиком в одном файле; цена ей — 55 повторяющихся функций на 202 в flang/stdlib, flang/examples/leetcode и flang/examples/rosetta.",
66
"решено": 26,
77
"тотальных решений": 24,
88
"категории": [
@@ -861,6 +861,10 @@
861861
"чего": "параметрический полиморфизм",
862862
"пояснение": "«Обратить» для списка числа и для списка строки — две разные функции с одинаковым телом. Опциональное значение приходится заводить отдельно под каждый тип, а имена вариантов обязаны быть уникальны в модуле."
863863
},
864+
{
865+
"чего": "функции первого класса в программах репозитория",
866+
"пояснение": "У ЯЗЫКА они есть: функция становится значением, применение проверяется по типам и арности, анализ завершаемости работает на высшем порядке, и все восемь целей печатают это дефункционализацией (flang/cat/HOF.md, фазы 1 и 3). А ПОЛЬЗОВАТЬСЯ ими ни stdlib, ни examples не вправе: flang/self/parser.flang новой формы не разбирает, а корпус сверки самоприменения собирается по маске каталога — первый же такой файл роняет пять тестов (три в self-bootstrap, два в self-parser) с диагностикой flang₁ «FLANG_PARSE: не разобрана конструкция: ожидался тип». Проверено запуском, а не рассуждением. Ровно та же граница держит и параметрический полиморфизм. Из-за неё «Все не меньше» и «Любой не меньше» в lists.flang остаются двумя функциями под один предикат, «Минимум» и «Максимум» — двумя телами одной свёртки, а «Сортировать» знает один порядок. Готовая замена всему этому написана и проверена целиком (36 функций, все тотальные, 55 примеров, печать во все восемь целей, сверка с интерпретатором на 179 точках) и ждёт в flang/test/stdlib-hof.test.mjs."
867+
},
864868
{
865869
"чего": "обработка ошибок",
866870
"пояснение": "Отказ встроенной формы («к числу» от «abc», «голова» от пустого списка) прекращает вычисление целиком и не перехватывается. Проверять пригодность аргумента приходится заранее, а выразить эту проверку удаётся не всегда."

flang/stdlib/lists.flang

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,32 @@
22

33
// Списки чисел: длина, обращение, соединение, срез, поиск, свёртки, сортировка.
44
//
5-
// Почему модуль про числа, а не «про любой список»: типы в flang не
6-
// параметрические (SPEC, раздел 3), а функции не являются значениями. Поэтому
7-
// «Сортировать» для строк — это отдельная функция с отдельным телом, а не
8-
// та же самая с другим параметром типа. Здесь взят самый частый случай —
9-
// список числа; для списка строки те же приёмы повторяются дословно.
5+
// Почему модуль про числа, а не «про любой список», и почему свёртка не берёт
6+
// функцию аргументом. Здесь стояло «функции не являются значениями» — это
7+
// БОЛЬШЕ НЕ ПРАВДА про язык: функция стала значением (flang/cat/HOF.md, фаза 1)
8+
// и печатается во все восемь целей (фаза 3). Проверено запуском: модуль с
9+
// `функция из числа в число` разбирается, проходит типы, доказывается
10+
// тотальным и считает верно.
11+
//
12+
// Правда — про РЕПОЗИТОРИЙ, и она уже: ни stdlib, ни examples не вправе
13+
// использовать ни функции-значения, ни параметрические типы, пока их не
14+
// понимает `flang/self/parser.flang`. Корпус сверки самоприменения собирается
15+
// по маске каталога, поэтому первый же такой файл здесь ломает неподвижную
16+
// точку. Это не осторожность: тот же модуль, положенный в flang/stdlib,
17+
// роняет пять тестов — три в self-bootstrap и два в self-parser, с
18+
// диагностикой flang₁ «FLANG_PARSE: не разобрана конструкция: ожидался тип».
19+
// Полиморфизм заплатил за это тремя упавшими тестами (flang/cat/POLY.md).
20+
//
21+
// Готовая библиотека на функциях-значениях уже написана и проверена целиком —
22+
// 36 функций, все тотальные, 55 примеров, печать во все восемь целей, сверка с
23+
// интерпретатором на 179 точках, — и лежит там, где корпус её не видит:
24+
// flang/test/stdlib-hof.test.mjs. Туда же вынесена улика, которая покраснеет,
25+
// когда `self/` научится, и потребует перенести модуль сюда.
26+
//
27+
// Пока этого нет: «Сортировать» для строк — отдельная функция с отдельным
28+
// телом, а «Все не меньше» и «Любой не меньше» — отдельные функции под
29+
// отдельный предикат. Здесь взят самый частый случай — список числа; для
30+
// списка строки те же приёмы повторяются дословно.
1031
//
1132
// Приписать элемент в начало списка встроенной формой нельзя: «добавить … к …»
1233
// дописывает в конец. Поэтому «Приписать в начало» — первая функция модуля:
@@ -171,9 +192,12 @@
171192
ожидается нет
172193
элементы содержит значение
173194

174-
// «все» и «любой» в языке без функций высшего порядка приходится писать
175-
// отдельно под каждый предикат: передать предикат некому. Здесь взят самый
176-
// частый — сравнение с порогом.
195+
// «все» и «любой» здесь написаны под ОДИН предикат — сравнение с порогом.
196+
// Причина не в языке: передать предикат теперь есть чем («Все» и «Любой»,
197+
// принимающие `функция из числа в признак`, написаны и проверены в
198+
// flang/test/stdlib-hof.test.mjs, и там же сверено, что они дают ровно то же,
199+
// что эти две). Причина в границе, названной в шапке модуля: файл входит в
200+
// корпус сверки самоприменения, а `self/parser.flang` этой формы не знает.
177201
тотальная функция «Все не меньше»
178202
принимает элементы: список числа, порог: число
179203
возвращает признак

flang/stdlib/optional.flang

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,20 @@
99
//
1010
// Два обстоятельства видны прямо в коде модуля.
1111
//
12-
// 1. Типы не параметрические: «Есть» с полем любого типа записать нельзя,
13-
// поэтому здесь именно «Число или ничто». Для строк пришлось бы завести
14-
// второй тип с другими именами вариантов — имена вариантов обязаны быть
15-
// уникальны в модуле (types.mjs).
12+
// 1. Здесь стояло: «типы не параметрические, «Есть» с полем любого типа
13+
// записать нельзя». Про ЯЗЫК это больше не правда — проверено запуском:
14+
// `тип «Возможно» от «А»` разбирается, проходит типы и обслуживает разом
15+
// `«Возможно» от числа` и `«Возможно» от строки`, одной суммой вместо двух
16+
// (flang/cat/POLY.md, фаза 1 сделана).
17+
//
18+
// Правда про РЕПОЗИТОРИЙ, и она уже: этот файл входит в корпус сверки
19+
// самоприменения, а `flang/self/parser.flang` параметрических типов не
20+
// разбирает — первый же такой файл здесь роняет неподвижную точку, чем
21+
// полиморфизм уже заплатил три упавших теста. Поэтому тип остаётся
22+
// непараметрическим — «Число или ничто», — и для строк пришлось бы завести
23+
// второй с другими именами вариантов: имена вариантов обязаны быть
24+
// уникальны в модуле (types.mjs). Схлопнется это в одну сумму сразу, как
25+
// только `self/` научится (POLY.md, фаза 5).
1626
//
1727
// 2. Здесь было записано, что у функций с вариантом примеров быть не может:
1828
// будто parseLiteralValue сворачивает конструктор в запись и теряет имя

0 commit comments

Comments
 (0)