Skip to content

feat(stdlib): russian morphology answers a dictionary entry or a gap - #313

Merged
the-homeless-god merged 3 commits into
devfrom
a/russian-morphology-for-syllogisms
Oct 4, 2026
Merged

the-homeless-god merged 3 commits into
devfrom
a/russian-morphology-for-syllogisms

Conversation

@the-homeless-god

@the-homeless-god the-homeless-god commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Модуль русской морфологии, на котором потом встанет снятие объявлений из текстов силлогизмов. Переводчик предложений не тронут ни строкой — его правку делает отдельная работа.

Что сделано

flang/stdlib/ru-morphology.flang читает одну русскую словоформу и отвечает записью словаря того вида, который разбирает translator.flang: класс слова, формы по числу, формы по роду. Где форма читается двояко — все чтения и слова, чем их различить. Где правило формы не выводит — названная недостача со списком того, что дали бы правила. Молчаливой догадки нет нигде.

порог факт откуда
корпус не меньше 60 слов 83 ru-morphology:probe
из них отказов с названной неопределённостью, не меньше 8 60 тот же прогон
согласование в обе стороны 14 проверок agreement.tsv
расхождений 0 ru-morphology: слов 83, согласований 14, отказов 60, разошлось 0
утверждений / доказано / сетка / не доказано 51 / 51 / 0 / 0 check --proof, код 0
функций, все тотальные 112 вместе с ввозом check: завершение доказано у всех
подлог краснит набор код 1 ru-morphology:forgery
контрольный прогон переводчика проб 14, разошлось 0, 16,0 с не изменился
битых путей в прозе 90 из 6941 на базе → 90 из 6947 на ветке links:check на обоих деревьях

У каждой строки корпуса третье поле — подлог: подменённая форма, на которой ответ обязан отличаться. Правило, на подмене которого ответ не меняется, ничего не проверяет, и набор называет его словами «правило не проверено». Отрицательный контроль снят трижды: подлог, равный самой форме, на кит и на смертен даёт разошлось 1 и имя правила; перестановка wanted и rejected в согласовании даёт разошлось 2. Корпус снимается планом Snap и воспроизводится им байт в байт.

Два ответа на вопрос «что невозможно без словаря»

  1. Класс слова по форме у частых окончаний не читается. Мужская краткая форма — голая основа, от существительного мужского рода формой неотличима: кит читается и понятием, и свойством. 60 слов из 83 отказываются; ровно одним чтением решаются 23. Однозначно решается формой только полное прилагательное (-ый -ая -ое -ые).
  2. Множественное существительного не выводится ни для одного слова. кит → киты правило даёт, человек → люди не даёт никакое, и по форме эти случаи одинаковы. Строка Понятие: X, Xs остаётся нужной целиком.

Поэтому объявление не отменяется, а становится уточнением поверх вывода. Что снять всё-таки можно: у краткого прилагательного без беглой гласной три остальные формы выводятся — Свойство: мохнат, мохнаты; она мохната; оно мохнато сводится к Свойство: мохнат. С беглой гласной (смертен против зелен) — нет, и там строка нужна по-прежнему.

Одушевлённость не читается никогда (доказанное постусловие), и тире ставит не она, а класс слова: «окно — вещь» и «кит — животное» идут с тире одинаково.

Файлы

  • flang/stdlib/ru-morphology.flang — новый модуль
  • flang/proof/probes/ru-morphology/ — набор проб: run.fscript, forms.tsv, agreement.tsv
  • docs/ru-grammar.md — что умеет и, обязательным разделом, чего не умеет (14 пунктов)
  • docs/adr/0060-… — решение, состояние «предложено»
  • .flangrc — три короткие команды; .github/workflows/binary.yml — два шага рядом с пробой переводчика, подлог в условии if
  • scripts/ledgers/proved-share-ledger.txt, scripts/ledgers/file-name-words.txt — по строке
  • счётные приметы: 24 места, сдвинутые ростом библиотеки, сняты приборами prose-numbers-guard и published-vs-tree.sh

Чего в этой ветке нет

Шаг стоит в binary.yml, а не в ci.yml: работа «CI» на GitHub отключена вручную (gh workflow list → disabled_manually), и поставленный туда шаг не прогонялся бы вовсе. Модуля нет в справочнике docs/site/stdlib.md (там только счёт поправлен) и нет ни в одном профиле flang/stdlib/profiles.flangrc. Составные понятия (морское животное, дышит жабрами) прибор не берёт — они остаются за человеком целиком.


Дополнение: модуль переехал в опытные, и к нему есть живой пример

Просьба владельца: «про морфологию давай просто в экспериментальный модуль вынесем, сделаем в ./flang/experimental например и задачу и ADR заведем тоже, чтобы пример морфологии и силлогизмами уже показать что из этого выходит и как работает». Сделано тремя коммитами.

1. flang/stdlib/ru-morphology.flang → flang/experimental/ru-morphology.flang

Опытный каталог — не папка «на потом», а снятое обещание: имена функций в нём меняются без предупреждения. Что именно поедет, уже видно: тип «Reading» и функция «Forms of» объявлены и в морфологии, и в переводчике предложений, и файл, ввозящий оба модуля, компилятор отвергает — FLANG_DUPLICATE_NAME, замечаний 18, код 1. Разводить имена придётся в морфологии: переводчик старше, и его зовёт набор проб. В stdlib такое переименование было бы ломающей правкой библиотеки.

Каталог объявлен в docs/repository-layout.md и .ru.md — и в карте корня, и прозой: «опытные модули: не входят в обещания стандартной библиотеки, могут менять имена функций без предупреждения».

Починено ссылок: 5 мест пути (flang/proof/probes/ru-morphology/run.fscript, docs/ru-grammar.md дважды, docs/adr/0060-…, .github/workflows/binary.yml) плюс строка в scripts/ledgers/proved-share-ledger.txt (отпечаток md5 тот же — содержимое не менялось, переехал только путь, и строка встала на своё место в сортировке).

Числа библиотеки сняты прибором, а не арифметикой (bootstrap/flang io scripts/guards/prose-numbers-guard.fscript --plan Check, 4 октября 2026) — 19 мест в 10 файлах:

примета было стало
файлов flang/stdlib/*.flang 54 53
примеров-в flang/stdlib/*.flang 3917 3807
примеров-в flang/stdlib/*.flang,flang/core/*.flang 4101 3991
строк-в flang/stdlib/*.flang 34 392 33 153
функций в stdlib (счёт по исходнику) 1904 1793

После правки: примет 210: сошлось 210, разошлось 0.

2. Задача 8337

docs/tasks/8337-the-sentence-translator-asks-a-declaration-for-every-word.md — переводчик предложений требует объявления на каждое слово, хотя морфология половину словаря выводит сама. Нужность снята прогоном: в 14 текстах корпуса силлогизмов стоит 40 строк объявлений, написанных руками. В задаче названы и шаги воспроизведения столкновения имён, и обходной путь, которым пользуется пример, и признак готовности: check на файле с обоими ввозами отвечает «замечаний нет», объявлений в корпусе меньше 40, а все 14 приговоров expected.tsv не изменились.

3. Живой пример: flang/experimental/ru-syllogism-demo.fscript

Зов — bootstrap/flang run-script ru-syllogism:demo. Берёт русский текст без единого объявления, наполняет словарь морфологией, отдаёт готовый текст тому же судье силлогизмов (run.fscript --plan Judge, отдельным процессом) и печатает по-человечески: что понял сам, где язык двоится и нужна одна строка, где человек ошибся. Тексты — flang/experimental/texts/, три штуки.

Класс слова (понятие против свойства) морфология не выбирает и не будет: выбирает место в предложении, и теми же словами, какие морфология печатает при двух чтениях. Это синтаксис, поэтому правило лежит в примере, а не в модуле.

Прогон 4 октября 2026, код возврата 0, поручений 6. Ниже — поле result дословно (flang io печатает его одной строкой JSON; переносы в ней стоят как \n).

Словарь выведен целиком, заключение следует
── texts/follows.txt ──
текст, как его написал человек:
  1. Все мохнатые тихи.
  2. Барсик — мохнатый.
  3. Значит, Барсик тих.
что прибор прочитал сам, без единого объявления:
  Имя: Барсик
  Понятие: мохнатый, мохнатые
  Свойство: тих, тихи; она тиха; оно тихо
где язык двоится и нужна строка от человека:
  негде
приговор судьи, код 0:
  1. посылка: Все мохнатые тихи.
  2. посылка: Барсик — мохнатый.
  3. заключение: Следовательно, Барсик тих.
  СЛЕДУЕТ: предложение 3 выведено из посылок 1, 2
  ядро: ДОКАЗАНО — утверждений 1: доказано 1, условно 0, сетка 0, объявлено, не доказано 0, отвергнуто 0, нарушено 0; законов на сетке 0, на веру 0 — код возврата 0
Словарь неполон — просьба ровно одной строкой
── texts/asks-one-line.txt ──
текст, как его написал человек:
  1. Все люди тихи.
  2. Барсик — человек.
  3. Значит, Барсик тих.
что прибор прочитал сам, без единого объявления:
  Имя: Барсик
  Свойство: тих, тихи; она тиха; оно тихо
где язык двоится и нужна строка от человека:
  предложение 1, «люди»: по месту в предложении нужно понятие во множественном
    морфология даёт чтений 2 — различить: «понятие» — подлежащее или сказуемое через тире «свойство» — сказуемое без тире
    а формы не даёт: единственное существительного из множественного не выводится: «киты» дают «кит», а «люди» — «человек»; впишите форму руками
    допишите одну строку: Понятие: человек, люди
приговора нет: словарь неполон — допишите строку выше в текст и прогоните снова
Словарь выведен целиком, а рассуждение неверно — названо где
── texts/does-not-follow.txt ──
текст, как его написал человек:
  1. Все мохнатые тихи.
  2. Барсик тих.
  3. Значит, Барсик — мохнатый.
что прибор прочитал сам, без единого объявления:
  Имя: Барсик
  Свойство: тих, тихи; она тиха; оно тихо
  Понятие: мохнатый, мохнатые
где язык двоится и нужна строка от человека:
  негде
приговор судьи, код 1:
  1. посылка: Все мохнатые тихи.
  2. посылка: Барсик тих.
  3. заключение: Следовательно, Барсик — мохнатый.
  НЕ СЛЕДУЕТ: предложение 3 «Следовательно, Барсик — мохнатый.» не выведено из посылок 1, 2
  ядро: FLANG_PROOF_STEP, строка 16 проверенной программы — цель не выведена из допущений теоремы
  пример против, подсказка переводчика, ядром не проверена — «Барсик»: тих — да, мохнатый — нет

Чего пример не умеет — названо и в docs/ru-grammar.md, и примечанием в самом файле: составного сказуемого (дышит жабрами) он не берёт; род подлежащего считает мужским, и женское имя (Ксантиппа) проведёт неверно; строку-подсказку собирает из форм того же класса, найденных в этом же тексте, и при двух сломанных понятиях в одном тексте свела бы разные слова; из слов вывода знает только «Значит» и «Следовательно»; судью зовёт процессом, а не вызовом функции.

Куда это вписано

docs/ru-grammar.md — новый раздел «Что выходит на живом тексте» с дословным выводом и перечнем того, чего пример не умеет. docs/adr/0060-… — раздел 2 «Почему опытный, а не стандартный» и раздел 10 «Что выходит на живом тексте» с тем же прогоном; раздел 9 теперь называет задачу 8337. Имя файла ADR не менялось.

Прогоны

ru-syllogism:demo — код 0, поручений 6, текстов 3. ru-morphology:probe — слов 83, согласований 14, отказов 60, разошлось 0. check --proof flang/experimental/ru-morphology.flang — «ПРОВЕРЕНО САМОСТОЯТЕЛЬНО», утверждений 51: доказано 51, код 0. check flang/experimental/ru-syllogism-demo.fscript — замечаний нет, функций 197, завершение доказано у всех. lint — 0 строк сверх 120, 0 ветвлений сверх 2. Заслон перед пушем: все 21 проверки зелены за 53 с (prose-numbers-guard, proved-share-vs-tree, tree-inventory, task-ledger, shortcut-collector, lint-growth, no-growth и остальные). Сверх него: scripts:check, file-extensions:check, adr:numbers, tasks:numbers, cyrillic:check, transliteration:check, published-vs-tree.sh --карта — код 0 у каждого. links:check красен 90 ссылками на всём дереве и был красен до этой ветки; ни одна из них не из этих файлов.

@the-homeless-god
the-homeless-god force-pushed the a/russian-morphology-for-syllogisms branch 2 times, most recently from 7e5dbc3 to 8a452c1 Compare October 4, 2026 17:09
flang/stdlib/ru-morphology.flang reads ONE russian word form and answers the
dictionary entry the sentence translator parses: word class, forms by number,
forms by gender. Where the form reads two ways it returns every reading plus
the words that tell them apart; where no rule derives a form it returns a
named gap with the list of what the rules would give. It never guesses
silently: a silent guess grows a false syllogism and nobody is told.

Measured 2026-10-04 with bootstrap/flang 0.7.24 built in this tree.

  ru-morphology:probe   words 83, agreements 14, refusals 60, diverged 0
  check --proof         51 statements: 51 proved, 0 on a grid, 0 unproved
  functions             112 with the import, all total, termination proved
  ru-morphology:forgery code 1 - the probe reddens on a shifted corpus

No "--na-veru" key anywhere: the probe runs without consent to the unproven.
Getting there cost six weak length statements, traded for the examples of the
same functions, and two rewrites; ADR-0060 section 7 names all nine and the
price. The alternative was raising the run-verdict debt ceiling from 49 to 50.

Every corpus row carries a THIRD field: the bent form, on which the answer
must differ. A rule whose answer survives the bend checks nothing, and the
probe names it "pravilo ne provereno". Negative control taken: the word "kit"
with its own form as the bend gives diverged 1 and names the rule; reverting
gives diverged 0. Agreement is checked both ways and both reject the swapped
form; swapping wanted and rejected on one row gives diverged 2.

Two findings the owner needs before dropping the declarations:

  - word CLASS is not readable from the form at the common endings. A bare
    masculine short form is indistinguishable from a masculine noun: "kit"
    reads both as a notion and as a property. 60 of 83 corpus words refuse.
    Only a full adjective (-yj -aja -oe -ye) is decided by form alone.
  - the PLURAL of a noun is derivable for no word at all. "kit" gives "kity"
    by rule, "chelovek" gives "lyudi" by none, and the form does not say
    which case it is. So the "Ponyatie: X, Xs" line stays needed in full.

The declaration is therefore not removed but demoted to a correction over the
derivation. A short adjective WITHOUT a fugitive vowel does collapse to one
word: "Svojstvo: mohnat" is enough, the other three forms follow by rule.

Animacy is never read, and that is a proved postcondition: the dash before a
predicate is placed by the word class, not by animacy.

The probe is called from .github/workflows/binary.yml next to the sentence
probe, the forgery in an "if" so the step fails when the probe stayed silent.
Not from ci.yml: that workflow is disabled_manually on GitHub, so a step put
there would never run at all.

docs/ru-grammar.md carries the mandatory "what this module cannot do" section;
ADR-0060 carries the decision and how a proper name differs from a notion by
form, and how it does not.

The library grew by one module, so the counted marks moved: stdlib files
53 to 54, lines 33153 to 34392, examples 3807 to 3917 and 3991 to 4101,
tree .flang files 1127 to 1128, library functions 1793 to 1904. All taken by
the instrument, not by hand.

Control run unchanged: the sentence probe still answers
"syllogism/sentences: probes 14, diverged 0", code 0, 16.0 s.
Broken doc links: 90 of 6941 on the base, 90 of 6947 on the branch - no gain.
flang/stdlib/ru-morphology.flang -> flang/experimental/ru-morphology.flang.
An experimental module is NOT part of the promises of the standard library and
may change the names of its functions without warning. The morphology is exactly
that today, and keeping it in stdlib promised what is not there.

The new directory is declared in docs/repository-layout.md and .ru.md: in the
root map and in the prose about flang/.

Every number below was taken by the instrument, not by arithmetic
(prose-numbers-guard, 2026-10-04):

  files   flang/stdlib/*.flang        54 -> 53
  samples flang/stdlib/*.flang      3917 -> 3807
  samples stdlib + core             4101 -> 3991
  lines   flang/stdlib/*.flang     34392 -> 33153
  functions in stdlib (by source)   1904 -> 1793

Runs: ru-morphology:probe "words 83, agreements 14, refusals 60, diverged 0";
check --proof flang/experimental/ru-morphology.flang - 51 statements, 51 proved,
code 0; prose-numbers-guard - 210 marks, 0 diverged; published-vs-tree --karta -
agrees; inventory:check - agrees; proved-share-vs-tree - agrees.
flang/experimental/ru-syllogism-demo.fscript (run-script ru-syllogism:demo)
takes INFORMAL russian with no declaration of a notion, a property or a name,
fills the dictionary with the morphology, and hands the result to the same
syllogism judge. It prints three things: what it read on its own, where the
language reads two ways and one line from a human is needed, and the verdict in
the judge's own words. Three texts next to it in flang/experimental/texts/.

Measured 2026-10-04, bootstrap/flang 0.7.24 in this tree: exit code 0, orders 6,
three texts. On texts/follows.txt the whole dictionary came out of the forms -
"Imya: Barsik", "Ponyatie: mohnatyj, mohnatye", "Svojstvo: tih, tihi; ona tiha;
ono tiho" - and the kernel answered DOKAZANO. On texts/asks-one-line.txt exactly
ONE question was left and exactly one line was asked for. On
texts/does-not-follow.txt the dictionary came out whole and the reasoning is
wrong, and the place is named: sentence 3 is not derived from 1 and 2, with a
counterexample.

The word class is NOT chosen by the morphology: it is chosen by the place in the
sentence, with the very words the morphology prints for two readings. That is
syntax, so the rule lives in the demo, not in the module.

The judge is spawned as a process, not called as a function: both modules
declare a type "Reading", and a file importing both is refused -
FLANG_DUPLICATE_NAME, 18 findings, code 1. Task 8337 carries the rename and the
translator's move onto this dictionary.

docs/tasks/8337-the-sentence-translator-asks-a-declaration-for-every-word.md:
the translator asks a declaration for every word, while 40 declaration lines sit
in 14 corpus texts by hand. docs/ru-grammar.md gets the run verbatim in a
section of its own; ADR-0060 gets section 2 "why experimental, not standard" and
section 10 with the same run.

Runs: ru-syllogism:demo code 0; check flang/experimental/ru-syllogism-demo.fscript
- no findings, 197 functions, termination proved for all; check --proof - 0
statements, code 0; lint - 0 over the limits; tasks:check - 183 tasks whole;
tasks:numbers - 0 double numbers; inventory:check, scripts:check,
file-extensions:check, proved-share-vs-tree, record-follows-its-source,
guards-without-forgery-probe, version-derivations-guard - all agree.
@the-homeless-god
the-homeless-god force-pushed the a/russian-morphology-for-syllogisms branch from 726b37a to 6f13dc8 Compare October 4, 2026 19:00
@the-homeless-god
the-homeless-god merged commit 032fb5f into dev Oct 4, 2026
32 checks passed
@the-homeless-god
the-homeless-god deleted the a/russian-morphology-for-syllogisms branch October 4, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant