DigitableCourses

flang · @digitable/fts@0.4.0 · открытый исходный код

Тотальный язык на обычных задачах: 26 решений LeetCode, у 20 завершение доказано компилятором.

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

26
решений в репозитории языка
20
с доказанным завершением
62/77
тотальных функций
135/135
примеров сходится

Зачем эта страница

Не «мы умеем решать задачки», а проверка языка на территории, для которой он не задумывался.

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

  1. 01Код настоящийФайлы читаются из репозитория языка при сборке страницы. Переписать их «покрасивее» физически нельзя: копия сверяется с источником побайтно.
  2. 02Числа сняты запускомТотальность даёт flang check, сходимость примеров — flang test. Каждое решение прогоняется, а не пересказывается.
  3. 03Гарантия сильнее тестаОбычно алгоритм пишут циклом, а уверенность в его конечности берут из тестов. Здесь у 20 решений завершение доказано при проверке типов.
  4. 04Границы названы6 решения тотальными не вышли, а 12 задачи в языке не выражаются вовсе. Обе цифры на этой же странице, ниже.

Что именно гарантируется

«Тотальная» — это не стиль и не соглашение. Это отказ компилятора принять функцию, конец которой он не доказал.

Функция объявляется словом тотальная, и дальше проверка ищет структурное убывание: каждый рекурсивный вызов обязан получить часть разобранного значения — хвост списка, поддерево, меньшую запись. Если убывания нет, модуль не проходит flang check и до запуска дело не доходит. Поэтому у тотального решения зацикливания не бывает не «по опыту», а по построению.

Что даёт тотальность

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

Чего она не даёт

  • правильности: тотальная функция может честно завершиться и вернуть неверное число — за это отвечают примеры;
  • сложности: доказано, что вычисление кончится, а не что оно кончится быстро. Без хеш-таблиц часть решений остаётся квадратичной;
  • универсальности: 6 решения из 26 тотальными сделать не удалось.

Где доказательства нет и почему

Честнее показать эти решения рядом с остальными, чем спрятать. Каждое из них проходит типизацию и все свои примеры — не хватает ровно доказательства конечности.

  • 13 Римское в число Свёртка с записью-состоянием (сумма и предыдущая цифра). Нетотальна только из-за разложения строки в список символов. тотальны 2 из 4 функций · примеров 9/9
  • 14 Наибольший общий префикс Свёртка по словам поверх посимвольного сравнения двух слов. Сравнение идёт рекурсией по номеру позиции — её анализ убывания не принимает. тотальны 0 из 3 функций · примеров 7/7
  • 20 Правильные скобки Стек живёт строкой в накопителе свёртки, поломка запоминается префиксом «!». Списочная версия тотальна, строковая — нет. тотальны 3 из 5 функций · примеров 12/12
  • 70 Ступени Линейный проход с двумя накопителями. Нетотальна: счётчик «осталось минус 1» — результат арифметики, а не часть значения. тотальны 0 из 2 функций · примеров 5/5
  • 125 Палиндром Нижний регистр — таблицей из двух алфавитов: встроенной формы «код символа» нет. Нетотальна из-за обхода символов; кириллица решением не покрыта. тотальны 3 из 7 функций · примеров 12/12
  • 509 Фибоначчи Линейный вариант с двумя накопителями. Нетотальна ровно из-за счётчика: убывания по числу анализ не знает. тотальны 0 из 2 функций · примеров 6/6

Каталог решений

26 задач: условие, приём, гарантия, код.

Раскройте карточку — под ней лежит полный файл решения из flang/examples/leetcode. Связывания модулей в языке нет, поэтому вспомогательные функции повторяются в каждом файле: решение самодостаточно и запускается как есть командой flang test.

1 Две суммы Two Sum завершение доказано списки 6/6 примеров 3/3 функций тотальны 65 строк

Вместо словаря «значение → номер» — вложенный проход: для каждой головы ищем дополнение в хвосте. O(n²) как прямая цена отсутствия хеш-таблиц.

flang check
модуль «Две суммы» проходит проверку типов. Главная функция «Две суммы» тотальна: компилятор принял доказательство завершения.
flang test
6 примеров в файле, сошлось 6, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Позиция значениятотальная
  • Поиск пары с позициитотальная
  • Две суммытотальная
examples/flang/leetcode/001-two-sum.flang3500 байт · sha256 8f1a940cc7b84f1c
модуль «Две суммы»

// LeetCode 1. Two Sum.
// Дан список чисел и цель. Найти два разных элемента, дающих в сумме цель,
// и вернуть их номера. Номера — с нуля, как в условии задачи; язык нумерует
// строки с единицы, поэтому пересчёт делается один раз, в конце.
//
// Тотальная. Хеш-таблиц в языке нет, поэтому вместо словаря «значение → номер»
// работает вложенный проход: для каждой головы ищем дополнение в хвосте.
// Это O(n²) вместо O(n) — прямая цена отсутствия ассоциативного массива.

тотальная функция «Позиция значения»
  принимает элементы: список числа, нужное: число
  возвращает число
  пример «Найдено вторым»
    дано элементы равно [5, 7]
    дано нужное равно 7
    ожидается 2
  пример «Не найдено»
    дано элементы равно [5, 7]
    дано нужное равно 9
    ожидается 0
  разбор элементов
    случай пусто
      то 0
    случай голова и хвост
      если голова равен нужное
        то 1
        иначе
          пусть дальше равно «Позиция значения» от хвост и нужное
          если дальше равен 0 то 0 иначе дальше плюс 1

тотальная функция «Поиск пары с позиции»
  принимает элементы: список числа, цель: число, позиция: число
  возвращает список числа
  пример «Пара в начале»
    дано элементы равно [2, 7, 11]
    дано цель равно 9
    дано позиция равно 0
    ожидается [0, 1]
  разбор элементов
    случай пусто
      то пустой список
    случай голова и хвост
      пусть смещение равно «Позиция значения» от хвост и (цель минус голова)
      если смещение больше 0
        то [позиция, позиция плюс смещение]
        иначе «Поиск пары с позиции» от хвост и цель и (позиция плюс 1)

тотальная функция «Две суммы»
  принимает элементы: список числа, цель: число
  возвращает список числа
  пример «Пример 1 из условия»
    дано элементы равно [2, 7, 11, 15]
    дано цель равно 9
    ожидается [0, 1]
  пример «Пример 2 из условия»
    дано элементы равно [3, 2, 4]
    дано цель равно 6
    ожидается [1, 2]
  пример «Пример 3 из условия»
    дано элементы равно [3, 3]
    дано цель равно 6
    ожидается [0, 1]
  «Поиск пары с позиции» от элементы и цель и 0
13 Римское в число Roman to Integer доказательства нет строки 9/9 примеров 2/4 функций тотальны 94 строк

Свёртка с записью-состоянием (сумма и предыдущая цифра). Нетотальна только из-за разложения строки в список символов.

flang check
модуль «Римские числа» проходит проверку типов, объявлено типов: 1. Главная функция «Римское в число» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
9 примеров в файле, сошлось 9, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать строку в началототальная
  • Значение цифрытотальная
  • Символы с позициибез доказательства
  • Римское в числобез доказательства
examples/flang/leetcode/013-roman-to-integer.flang4973 байт · sha256 604a4018427517ef
модуль «Римские числа»

// LeetCode 13. Roman to Integer.
// Перевести римскую запись в число.
//
// Обычная, не тотальная — и виновата только строка. Сам разбор («если
// предыдущая цифра меньше текущей, вычесть её дважды») выражается свёрткой
// с записью-состоянием и тотален; но чтобы получить символы строки, её надо
// обойти по одному, а убывание «строка стала короче на символ» анализ
// завершаемости не признаёт: часть значения — это хвост списка, голова,
// поле записи или поле варианта, и ничего больше.
//
// Была бы встроенная форма «символы строки», задача стала бы тотальной
// целиком.

объект «Разбор римского»
  сумма является числом
  предыдущее является числом

тотальная функция «Приписать строку в начало»
  принимает первая: строка, элементы: список строки
  возвращает список строки
  пример «В непустой»
    дано первая равно "I"
    дано элементы равно ["V"]
    ожидается ["I", "V"]
  свёртка элементы начиная с [первая] как акк и эл → добавить эл к акк

тотальная функция «Значение цифры»
  принимает буква: строка
  возвращает число
  пример «Единица»
    дано буква равно "I"
    ожидается 1
  пример «Тысяча»
    дано буква равно "M"
    ожидается 1000
  пример «Не римская цифра»
    дано буква равно "щ"
    ожидается 0
  если буква равен "I"
    то 1
    иначе
      если буква равен "V"
        то 5
        иначе
          если буква равен "X"
            то 10
            иначе
              если буква равен "L"
                то 50
                иначе
                  если буква равен "C"
                    то 100
                    иначе
                      если буква равен "D"
                        то 500
                        иначе
                          если буква равен "M" то 1000 иначе 0

функция «Символы с позиции»
  принимает текст: строка, позиция: число
  возвращает список строки
  пример «С последнего символа»
    дано текст равно "IV"
    дано позиция равно 2
    ожидается ["V"]
  если позиция больше (длина текст)
    то пустой список
    иначе
      пусть буква равно подстрока текст с позиция по позиция
      «Приписать строку в начало» от буква и («Символы с позиции» от текст и (позиция плюс 1))

функция «Римское в число»
  принимает текст: строка
  возвращает число
  пример «Пример 1 из условия»
    дано текст равно "III"
    ожидается 3
  пример «Пример 2 из условия»
    дано текст равно "LVIII"
    ожидается 58
  пример «Пример 3 из условия»
    дано текст равно "MCMXCIV"
    ожидается 1994
  пример «Вычитание»
    дано текст равно "IV"
    ожидается 4
  пусть начальное равно запись «Разбор римского» с сумма равным 0 и предыдущее равным 0
  пусть итог равно свёртка («Символы с позиции» от текст и 1) начиная с начальное как акк и буква
    пусть значение равно «Значение цифры» от буква
    пусть поправка равно если акк.предыдущее меньше значение то (2 умножить на акк.предыдущее) иначе 0
    запись «Разбор римского» с сумма равным (акк.сумма плюс значение минус поправка) и предыдущее равным значение
  итог.сумма
14 Наибольший общий префикс Longest Common Prefix доказательства нет строки 7/7 примеров 0/3 функций тотальны 60 строк

Свёртка по словам поверх посимвольного сравнения двух слов. Сравнение идёт рекурсией по номеру позиции — её анализ убывания не принимает.

flang check
модуль «Общий префикс» проходит проверку типов. Главная функция «Наибольший общий префикс» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
7 примеров в файле, сошлось 7, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Общий префикс до позициибез доказательства
  • Общий префикс двухбез доказательства
  • Наибольший общий префиксбез доказательства
examples/flang/leetcode/014-longest-common-prefix.flang3506 байт · sha256 8a6a21d6882218db
модуль «Общий префикс»

// LeetCode 14. Longest Common Prefix.
// Найти наибольший общий начальный кусок для списка слов.
//
// Обычная. Свёртка по списку слов тотальна, а вот сравнение двух слов идёт
// по позициям — рекурсия по числу, которую анализ завершаемости не
// принимает: «позиция плюс 1» не является частью значения «позиция».
// Ни один известный приём здесь не спасает: топливо (см. задачу 704) можно
// было бы взять из списка слов, но длина слова с длиной списка не связана.

функция «Общий префикс до позиции»
  принимает первое: строка, второе: строка, позиция: число
  возвращает строка
  пример «Совпало два символа»
    дано первое равно "flower"
    дано второе равно "flow"
    дано позиция равно 1
    ожидается "flow"
  пусть предел равно если (длина первое) меньше (длина второе) то (длина первое) иначе (длина второе)
  если позиция больше предел
    то подстрока первое с 1 по предел
    иначе
      если (подстрока первое с позиция по позиция) равен (подстрока второе с позиция по позиция)
        то «Общий префикс до позиции» от первое и второе и (позиция плюс 1)
        иначе подстрока первое с 1 по (позиция минус 1)

функция «Общий префикс двух»
  принимает первое: строка, второе: строка
  возвращает строка
  пример «Общее начало»
    дано первое равно "flower"
    дано второе равно "flight"
    ожидается "fl"
  пример «Ничего общего»
    дано первое равно "dog"
    дано второе равно "racecar"
    ожидается ""
  «Общий префикс до позиции» от первое и второе и 1

функция «Наибольший общий префикс»
  принимает слова: список строки
  возвращает строка
  пример «Пример 1 из условия»
    дано слова равно ["flower", "flow", "flight"]
    ожидается "fl"
  пример «Пример 2 из условия»
    дано слова равно ["dog", "racecar", "car"]
    ожидается ""
  пример «Одно слово»
    дано слова равно ["abc"]
    ожидается "abc"
  пример «Пустой список»
    дано слова равно пустой список
    ожидается ""
  разбор слова
    случай пусто
      то ""
    случай голова и хвост
      свёртка хвост начиная с голова как акк и слово → «Общий префикс двух» от акк и слово
20 Правильные скобки Valid Parentheses доказательства нет строки 12/12 примеров 3/5 функций тотальны 99 строк

Стек живёт строкой в накопителе свёртки, поломка запоминается префиксом «!». Списочная версия тотальна, строковая — нет.

flang check
модуль «Правильные скобки» проходит проверку типов. Главная функция «Скобки в строке» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
12 примеров в файле, сошлось 12, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать строку в началототальная
  • Парная открывающаятотальная
  • Скобки в спискетотальная
  • Символы с позициибез доказательства
  • Скобки в строкебез доказательства
examples/flang/leetcode/020-valid-parentheses.flang5305 байт · sha256 12cb0b94859ab787
модуль «Правильные скобки»

// LeetCode 20. Valid Parentheses.
// Проверить, что скобки трёх видов закрываются в правильном порядке.
//
// Две функции нарочно. «Скобки в списке» принимает список символов и
// тотальна: стек живёт в накопителе свёртки (обычной строкой — стек строк
// потребовал бы отдельного типа), а свёртка конечна по построению.
// «Скобки в строке» принимает строку, как в условии, и тотальной быть не
// может: чтобы получить символы, строку надо обойти, а убывание строки
// анализ завершаемости не признаёт — «пусто» и «голова и хвост» работают
// только со списком.
//
// Прерывать свёртку нельзя, поэтому ошибка запоминается в самом стеке:
// строка, начинающаяся с «!», означает «уже сломано».

тотальная функция «Приписать строку в начало»
  принимает первая: строка, элементы: список строки
  возвращает список строки
  пример «В непустой»
    дано первая равно "а"
    дано элементы равно ["б"]
    ожидается ["а", "б"]
  свёртка элементы начиная с [первая] как акк и эл → добавить эл к акк

тотальная функция «Парная открывающая»
  принимает закрывающая: строка
  возвращает строка
  пример «Круглая»
    дано закрывающая равно ")"
    ожидается "("
  пример «Квадратная»
    дано закрывающая равно "]"
    ожидается "["
  если закрывающая равен ")"
    то "("
    иначе
      если закрывающая равен "]" то "[" иначе "{"

тотальная функция «Скобки в списке»
  принимает символы: список строки
  возвращает признак
  пример «Пример 1 из условия»
    дано символы равно ["(", ")"]
    ожидается да
  пример «Пример 2 из условия»
    дано символы равно ["(", ")", "[", "]", "{", "}"]
    ожидается да
  пример «Пример 3 из условия»
    дано символы равно ["(", "]"]
    ожидается нет
  пример «Незакрытая скобка»
    дано символы равно ["(", "["]
    ожидается нет
  пусть стек равно свёртка символы начиная с "" как акк и буква
    если акк начинается с "!"
      то акк
      иначе
        если "([{" содержит буква
          то соединить акк с буква
          иначе
            если (длина акк) равен 0
              то "!"
              иначе
                пусть верх равно подстрока акк с (длина акк) по (длина акк)
                если верх равен («Парная открывающая» от буква)
                  то подстрока акк с 1 по ((длина акк) минус 1)
                  иначе "!"
  стек равен ""

функция «Символы с позиции»
  принимает текст: строка, позиция: число
  возвращает список строки
  пример «С последнего символа»
    дано текст равно "()"
    дано позиция равно 2
    ожидается [")"]
  если позиция больше (длина текст)
    то пустой список
    иначе
      пусть буква равно подстрока текст с позиция по позиция
      «Приписать строку в начало» от буква и («Символы с позиции» от текст и (позиция плюс 1))

функция «Скобки в строке»
  принимает текст: строка
  возвращает признак
  пример «Пример 1 из условия»
    дано текст равно "()"
    ожидается да
  пример «Пример 2 из условия»
    дано текст равно "()[]{}"
    ожидается да
  пример «Пример 3 из условия»
    дано текст равно "(]"
    ожидается нет
  пример «Вложенные скобки»
    дано текст равно "{[()]}"
    ожидается да
  «Скобки в списке» от («Символы с позиции» от текст и 1)
26 Удалить повторы Remove Duplicates from Sorted Array завершение доказано списки 4/4 примеров 2/2 функций тотальны 32 строк

Свёртка с проверкой «содержит». Изменения на месте нет: значения flang неизменяемы, возвращается новый список.

flang check
модуль «Удалить повторы» проходит проверку типов. Главная функция «Без повторов» тотальна: компилятор принял доказательство завершения.
flang test
4 примеров в файле, сошлось 4, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Без повторовтотальная
  • Сколько уникальныхтотальная
examples/flang/leetcode/026-remove-duplicates-from-sorted-array.flang1891 байт · sha256 0307f8287403d080
модуль «Удалить повторы»

// LeetCode 26. Remove Duplicates from Sorted Array.
// Из отсортированного списка убрать повторы. В условии просят изменить массив
// на месте и вернуть число уникальных; изменяемых массивов в языке нет и быть
// не может — значения flang неизменяемы, — поэтому возвращается новый список,
// а «число уникальных» вынесено отдельной функцией.
//
// Тотальная: свёртка по списку, рекурсии нет вовсе.

тотальная функция «Без повторов»
  принимает элементы: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано элементы равно [1, 1, 2]
    ожидается [1, 2]
  пример «Пример 2 из условия»
    дано элементы равно [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
    ожидается [0, 1, 2, 3, 4]
  свёртка элементы начиная с пустой список как акк и эл
    если акк содержит эл то акк иначе добавить эл к акк

тотальная функция «Сколько уникальных»
  принимает элементы: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [1, 1, 2]
    ожидается 2
  пример «Пустой список»
    дано элементы равно пустой список
    ожидается 0
  длина («Без повторов» от элементы)
35 Место вставки Search Insert Position завершение доказано поиск 3/3 примеров 1/1 функций тотальны 27 строк

Одна свёртка: счёт элементов меньше цели. O(n) вместо требуемого O(log n) — двоичный поиск в тотальном классе требует приёма с топливом.

flang check
модуль «Место вставки» проходит проверку типов. Главная функция «Место вставки» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Место вставкитотальная
examples/flang/leetcode/035-search-insert-position.flang1601 байт · sha256 222865fab75e7418
модуль «Место вставки»

// LeetCode 35. Search Insert Position.
// В отсортированном списке найти номер цели, а если её нет — номер, куда её
// следовало бы вставить. Номера с нуля, как в условии.
//
// Тотальная. Условие требует O(log n), здесь же один линейный проход:
// двоичный поиск в тотальном классе требует особого приёма (см. 704), а
// линейная свёртка доказывается сама. Ответ тот же, сложность хуже —
// и это честная цена, а не недосмотр.

тотальная функция «Место вставки»
  принимает элементы: список числа, цель: число
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [1, 3, 5, 6]
    дано цель равно 5
    ожидается 2
  пример «Пример 2 из условия»
    дано элементы равно [1, 3, 5, 6]
    дано цель равно 2
    ожидается 1
  пример «Пример 3 из условия»
    дано элементы равно [1, 3, 5, 6]
    дано цель равно 7
    ожидается 4
  свёртка элементы начиная с 0 как акк и эл → если эл меньше цель то акк плюс 1 иначе акк
49 Группировка анаграмм Group Anagrams завершение доказано строки 6/6 примеров 5/5 функций тотальны 70 строк

Подпись слова — свёртка по алфавиту с подсчётом через «разделить»; словарь заменён списком записей «Группа» с линейным поиском.

flang check
модуль «Группировка анаграмм» проходит проверку типов, объявлено типов: 1. Главная функция «Группировать анаграммы» тотальна: компилятор принял доказательство завершения.
flang test
6 примеров в файле, сошлось 6, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Счёт буквытотальная
  • Подписьтотальная
  • Есть группатотальная
  • Добавить словототальная
  • Группировать анаграммытотальная
examples/flang/leetcode/049-group-anagrams.flang4499 байт · sha256 3aab7957b768667b
модуль «Группировка анаграмм»

// LeetCode 49. Group Anagrams.
// Разложить слова по группам: в одной группе — слова из одних и тех же букв.
//
// Тотальная. Каноническое решение — словарь «подпись → список слов», а
// ассоциативных массивов в языке нет. Замена: список записей «Группа» и
// линейный поиск по ключу. Подпись слова тоже строится без обхода символов —
// свёрткой по алфавиту с подсчётом через «разделить» (тот же приём, что в
// задаче 242). Порядок групп — порядок первого появления.
//
// Цена отсутствия словаря: O(слов × групп × 26) вместо O(суммарной длины).

объект «Группа»
  ключ является строкой
  слова является список строки

тотальная функция «Счёт буквы»
  принимает текст: строка, буква: строка
  возвращает число
  пример «Две буквы a»
    дано текст равно "abac"
    дано буква равно "a"
    ожидается 2
  (длина (разделить текст по буква)) минус 1

тотальная функция «Подпись»
  принимает слово: строка
  возвращает строка
  пример «Анаграммы дают одну подпись»
    дано слово равно "eat"
    ожидается "1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,"
  пример «Другое слово — другая подпись»
    дано слово равно "bat"
    ожидается "1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,"
  свёртка ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] начиная с "" как акк и буква
    соединить (соединить акк с (к строке («Счёт буквы» от слово и буква))) с ","

тотальная функция «Есть группа»
  принимает группы: список «Группа», ключ: строка
  возвращает признак
  свёртка группы начиная с нет как акк и группа
    если акк равен да то да иначе группа.ключ равен ключ

тотальная функция «Добавить слово»
  принимает группы: список «Группа», ключ: строка, слово: строка
  возвращает список «Группа»
  если «Есть группа» от группы и ключ
    то
      отобразить группы как группа
        если группа.ключ равен ключ
          то запись «Группа» с ключ равным ключ и слова равным (добавить слово к группа.слова)
          иначе группа
    иначе добавить (запись «Группа» с ключ равным ключ и слова равным [слово]) к группы

тотальная функция «Группировать анаграммы»
  принимает слова: список строки
  возвращает список список строки
  пример «Пример 1 из условия»
    дано слова равно ["eat", "tea", "tan", "ate", "nat", "bat"]
    ожидается [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]]
  пример «Пример 2 из условия»
    дано слова равно [""]
    ожидается [[""]]
  пример «Пример 3 из условия»
    дано слова равно ["a"]
    ожидается [["a"]]
  пусть группы равно свёртка слова начиная с пустой список как акк и слово
    «Добавить слово» от акк и («Подпись» от слово) и слово
  отобразить группы как группа → группа.слова
53 Максимальная подпоследовательность Maximum Subarray завершение доказано динамика 4/4 примеров 1/1 функций тотальны 41 строк

Кадане: состояние из двух чисел укладывается в запись, запись — в накопитель свёртки. Единственная динамика, которая ложится на язык без сопротивления.

flang check
модуль «Максимальная подпоследовательность» проходит проверку типов, объявлено типов: 1. Главная функция «Наибольшая сумма куска» тотальна: компилятор принял доказательство завершения.
flang test
4 примеров в файле, сошлось 4, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Наибольшая сумма кускатотальная
examples/flang/leetcode/053-maximum-subarray.flang2740 байт · sha256 914be0f166ec0690
модуль «Максимальная подпоследовательность»

// LeetCode 53. Maximum Subarray.
// Найти наибольшую сумму непрерывного куска списка (алгоритм Кадане).
//
// Тотальная. Это самая «динамическая» из задач, которые язык принимает без
// сопротивления: состояние Кадане — два числа, а два числа складываются в
// запись, и запись отлично живёт накопителем свёртки. Настоящая динамика
// с таблицей (Coin Change, Edit Distance) так не переносится — там нужен
// массив с произвольным доступом по индексу, которого в языке нет.

объект «Состояние Кадане»
  текущая является числом
  лучшая является числом

тотальная функция «Наибольшая сумма куска»
  принимает элементы: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [-2, 1, -3, 4, -1, 2, 1, -5, 4]
    ожидается 6
  пример «Пример 2 из условия»
    дано элементы равно [1]
    ожидается 1
  пример «Пример 3 из условия»
    дано элементы равно [5, 4, -1, 7, 8]
    ожидается 23
  пример «Пустой список»
    дано элементы равно пустой список
    ожидается 0
  разбор элементов
    случай пусто
      то 0
    случай голова и хвост
      пусть начальное равно запись «Состояние Кадане» с текущая равным голова и лучшая равным голова
      пусть итог равно свёртка хвост начиная с начальное как акк и эл
        пусть продолженная равно акк.текущая плюс эл
        пусть текущая равно если продолженная больше эл то продолженная иначе эл
        пусть лучшая равно если текущая больше акк.лучшая то текущая иначе акк.лучшая
        запись «Состояние Кадане» с текущая равным текущая и лучшая равным лучшая
      итог.лучшая
66 Прибавить единицу Plus One завершение доказано списки 6/6 примеров 3/3 функций тотальны 57 строк

Перенос идёт справа налево, свёртка — слева направо, поэтому список обращается дважды. Обращение выражено свёрткой: встроенного «в начало» нет.

flang check
модуль «Прибавить единицу» проходит проверку типов, объявлено типов: 1. Главная функция «Прибавить единицу» тотальна: компилятор принял доказательство завершения.
flang test
6 примеров в файле, сошлось 6, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать в началототальная
  • Обратитьтотальная
  • Прибавить единицутотальная
examples/flang/leetcode/066-plus-one.flang3502 байт · sha256 216e595fc3dfe89e
модуль «Прибавить единицу»

// LeetCode 66. Plus One.
// Список цифр — большое число. Прибавить к нему единицу.
//
// Тотальная. Перенос идёт справа налево, а свёртка идёт слева направо,
// поэтому список сначала обращается, потом сворачивается, потом обращается
// обратно. Обращение выражается свёрткой, а не встроенной формой: приписать
// элемент в начало списка встроенным «добавить … к …» нельзя — оно
// дописывает в конец.

объект «Перенос»
  перенос является числом
  цифры является список числа

тотальная функция «Приписать в начало»
  принимает первый: число, элементы: список числа
  возвращает список числа
  пример «В непустой»
    дано первый равно 1
    дано элементы равно [2]
    ожидается [1, 2]
  свёртка элементы начиная с [первый] как акк и эл → добавить эл к акк

тотальная функция «Обратить»
  принимает элементы: список числа
  возвращает список числа
  пример «Три элемента»
    дано элементы равно [1, 2, 3]
    ожидается [3, 2, 1]
  свёртка элементы начиная с пустой список как акк и эл → «Приписать в начало» от эл и акк

тотальная функция «Прибавить единицу»
  принимает цифры: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано цифры равно [1, 2, 3]
    ожидается [1, 2, 4]
  пример «Пример 2 из условия»
    дано цифры равно [4, 3, 2, 1]
    ожидается [4, 3, 2, 2]
  пример «Пример 3 из условия»
    дано цифры равно [9]
    ожидается [1, 0]
  пример «Сплошные девятки»
    дано цифры равно [9, 9, 9]
    ожидается [1, 0, 0, 0]
  пусть начальное равно запись «Перенос» с перенос равным 1 и цифры равным пустой список
  пусть итог равно свёртка («Обратить» от цифры) начиная с начальное как акк и цифра
    пусть сумма равно цифра плюс акк.перенос
    пусть новая равно сумма остаток от 10
    пусть дальше равно если сумма не меньше 10 то 1 иначе 0
    запись «Перенос» с перенос равным дальше и цифры равным (добавить новая к акк.цифры)
  пусть результат равно «Обратить» от итог.цифры
  если итог.перенос равен 1
    то «Приписать в начало» от 1 и результат
    иначе результат
70 Ступени Climbing Stairs доказательства нет динамика 5/5 примеров 0/2 функций тотальны 45 строк

Линейный проход с двумя накопителями. Нетотальна: счётчик «осталось минус 1» — результат арифметики, а не часть значения.

flang check
модуль «Ступени» проходит проверку типов. Главная функция «Ступени» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
5 примеров в файле, сошлось 5, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Ступени шагомбез доказательства
  • Ступенибез доказательства
examples/flang/leetcode/070-climbing-stairs.flang2441 байт · sha256 f96bbfdf4c77750f
модуль «Ступени»

// LeetCode 70. Climbing Stairs.
// Сколькими способами подняться на n ступеней шагами по одной и по две.
//
// Обычная. Ответ — число Фибоначчи, и считается он за один проход с двумя
// накопителями; тотальной функция всё равно не становится, потому что
// «осталось минус 1» не является частью значения «осталось». Это та же
// граница, что в модуле stdlib/numbers.flang: рекурсия по числу анализу
// недоступна в принципе, ей нужна мера, а мер он не знает.
//
// Обход существует: передать список из n элементов и рекурсировать по нему.
// Но список из n элементов сам по себе строится рекурсией по n — то есть
// обычной функцией, и тотальность не спасена, а лишь передвинута.

функция «Ступени шагом»
  принимает осталось: число, предыдущее: число, текущее: число
  возвращает число
  пример «Один шаг»
    дано осталось равно 1
    дано предыдущее равно 1
    дано текущее равно 1
    ожидается 2
  если осталось не больше 0
    то текущее
    иначе «Ступени шагом» от (осталось минус 1) и текущее и (предыдущее плюс текущее)

функция «Ступени»
  принимает н: число
  возвращает число
  пример «Пример 1 из условия»
    дано н равно 2
    ожидается 2
  пример «Пример 2 из условия»
    дано н равно 3
    ожидается 3
  пример «Одна ступень»
    дано н равно 1
    ожидается 1
  пример «Десять ступеней»
    дано н равно 10
    ожидается 89
  если н не больше 1
    то 1
    иначе «Ступени шагом» от (н минус 1) и 1 и 1
88 Слияние отсортированных Merge Sorted Array завершение доказано списки 6/6 примеров 3/3 функций тотальны 59 строк

Не классическое слияние (оно убывает то по одному списку, то по другому и получает FLANG_NOT_TOTAL), а вставка в свёртке: O(n·m), зато доказуемо конечно.

flang check
модуль «Слияние отсортированных» проходит проверку типов. Главная функция «Слить отсортированные» тотальна: компилятор принял доказательство завершения.
flang test
6 примеров в файле, сошлось 6, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать в началототальная
  • Вставить по порядкутотальная
  • Слить отсортированныетотальная
examples/flang/leetcode/088-merge-sorted-array.flang3595 байт · sha256 c42dbe9146cd8a55
модуль «Слияние отсортированных»

// LeetCode 88. Merge Sorted Array.
// Слить два отсортированных списка в один отсортированный.
//
// Тотальная — но не тем алгоритмом, каким её пишут обычно. Классическое
// слияние рекурсирует то по первому списку, то по второму, и анализ
// завершаемости такой цикл отвергает: он требует ОДНУ позицию аргумента,
// убывающую на каждом рекурсивном вызове (totality.mjs, контрпример в шапке
// файла). Слияние даёт две разные позиции и получает FLANG_NOT_TOTAL.
//
// Поэтому здесь слияние вставками: «Вставить по порядку» рекурсирует ровно
// по хвосту второго аргумента, а внешний проход — свёртка. Результат тот же,
// сложность O(n·m) вместо O(n+m).

тотальная функция «Приписать в начало»
  принимает первый: число, элементы: список числа
  возвращает список числа
  пример «В непустой»
    дано первый равно 1
    дано элементы равно [2]
    ожидается [1, 2]
  свёртка элементы начиная с [первый] как акк и эл → добавить эл к акк

тотальная функция «Вставить по порядку»
  принимает значение: число, элементы: список числа
  возвращает список числа
  пример «В середину»
    дано значение равно 2
    дано элементы равно [1, 3]
    ожидается [1, 2, 3]
  пример «В пустой»
    дано значение равно 2
    дано элементы равно пустой список
    ожидается [2]
  разбор элементов
    случай пусто
      то [значение]
    случай голова и хвост
      если значение не больше голова
        то «Приписать в начало» от значение и элементы
        иначе «Приписать в начало» от голова и («Вставить по порядку» от значение и хвост)

тотальная функция «Слить отсортированные»
  принимает первый: список числа, второй: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано первый равно [1, 2, 3]
    дано второй равно [2, 5, 6]
    ожидается [1, 2, 2, 3, 5, 6]
  пример «Пример 2 из условия»
    дано первый равно [1]
    дано второй равно пустой список
    ожидается [1]
  пример «Пример 3 из условия»
    дано первый равно пустой список
    дано второй равно [1]
    ожидается [1]
  свёртка второй начиная с первый как акк и эл → «Вставить по порядку» от эл и акк
104 Глубина дерева Maximum Depth of Binary Tree завершение доказано деревья 3/3 примеров 4/4 функций тотальны 61 строк

Поле варианта — часть значения, поэтому рекурсия по поддеревьям доказывается сразу. Дерево в примерах строится из списка: вариант в «дано» не записать.

flang check
модуль «Глубина дерева» проходит проверку типов, объявлено типов: 1. Главная функция «Глубина из списка» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Вставить в деревототальная
  • Дерево из спискатотальная
  • Глубинатотальная
  • Глубина из спискатотальная
examples/flang/leetcode/104-maximum-depth-of-binary-tree.flang3734 байт · sha256 9077b460f11f9041
модуль «Глубина дерева»

// LeetCode 104. Maximum Depth of Binary Tree.
// Найти длину самого длинного пути от корня до листа.
//
// Тотальная. Дерево — сумма типов, а поле варианта анализ завершаемости
// считает частью значения, поэтому рекурсия по поддеревьям доказывается
// сразу и без ухищрений. Деревья язык принимает лучше, чем строки и числа.
//
// Дерево в примерах строится из списка: значение варианта нельзя записать
// в «дано» (парсер теряет имя конструктора), поэтому вход задаётся списком,
// а «Дерево из списка» превращает его в дерево поиска.

тип «Дерево»
  вариант Лист
  вариант Узел содержит значение: число, левое: «Дерево», правое: «Дерево»

тотальная функция «Вставить в дерево»
  принимает дерево: «Дерево», число: число
  возвращает «Дерево»
  разбор дерева
    случай Лист
      то Узел с значение равным число и левое равным вариант Лист и правое равным вариант Лист
    случай вариант Узел с значение как зн и левое как л и правое как п
      если число меньше зн
        то
          пусть новое равно «Вставить в дерево» от л и число
          Узел с значение равным зн и левое равным новое и правое равным п
        иначе
          пусть новое равно «Вставить в дерево» от п и число
          Узел с значение равным зн и левое равным л и правое равным новое

тотальная функция «Дерево из списка»
  принимает элементы: список числа
  возвращает «Дерево»
  свёртка элементы начиная с вариант Лист как акк и эл → «Вставить в дерево» от акк и эл

тотальная функция «Глубина»
  принимает дерево: «Дерево»
  возвращает число
  разбор дерева
    случай Лист
      то 0
    случай вариант Узел с левое как л и правое как п
      пусть слева равно «Глубина» от л
      пусть справа равно «Глубина» от п
      1 плюс (если слева больше справа то слева иначе справа)

тотальная функция «Глубина из списка»
  принимает элементы: список числа
  возвращает число
  пример «Сбалансированное дерево»
    дано элементы равно [2, 1, 3]
    ожидается 2
  пример «Цепочка»
    дано элементы равно [1, 2, 3, 4]
    ожидается 4
  пример «Пустое дерево»
    дано элементы равно пустой список
    ожидается 0
  «Глубина» от («Дерево из списка» от элементы)
110 Сбалансированное дерево Balanced Binary Tree завершение доказано деревья 3/3 примеров 5/5 функций тотальны 76 строк

Конъюнкция трёх условий записана вложенными «если»: логических «и» и «или» в языке нет.

flang check
модуль «Сбалансированное дерево» проходит проверку типов, объявлено типов: 1. Главная функция «Сбалансировано для списка» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Вставить в деревототальная
  • Дерево из спискатотальная
  • Глубинатотальная
  • Сбалансированототальная
  • Сбалансировано для спискатотальная
examples/flang/leetcode/110-balanced-binary-tree.flang4385 байт · sha256 2f753c379df468ba
модуль «Сбалансированное дерево»

// LeetCode 110. Balanced Binary Tree.
// Проверить, что для каждого узла глубины поддеревьев отличаются не более
// чем на единицу.
//
// Тотальная. Логических «и» и «или» в языке нет (SPEC перечисляет только
// арифметику и сравнения), поэтому конъюнкция трёх условий записана
// вложенными «если» — читается длиннее, но означает ровно то же.

тип «Дерево»
  вариант Лист
  вариант Узел содержит значение: число, левое: «Дерево», правое: «Дерево»

тотальная функция «Вставить в дерево»
  принимает дерево: «Дерево», число: число
  возвращает «Дерево»
  разбор дерева
    случай Лист
      то Узел с значение равным число и левое равным вариант Лист и правое равным вариант Лист
    случай вариант Узел с значение как зн и левое как л и правое как п
      если число меньше зн
        то
          пусть новое равно «Вставить в дерево» от л и число
          Узел с значение равным зн и левое равным новое и правое равным п
        иначе
          пусть новое равно «Вставить в дерево» от п и число
          Узел с значение равным зн и левое равным л и правое равным новое

тотальная функция «Дерево из списка»
  принимает элементы: список числа
  возвращает «Дерево»
  свёртка элементы начиная с вариант Лист как акк и эл → «Вставить в дерево» от акк и эл

тотальная функция «Глубина»
  принимает дерево: «Дерево»
  возвращает число
  разбор дерева
    случай Лист
      то 0
    случай вариант Узел с левое как л и правое как п
      пусть слева равно «Глубина» от л
      пусть справа равно «Глубина» от п
      1 плюс (если слева больше справа то слева иначе справа)

тотальная функция «Сбалансировано»
  принимает дерево: «Дерево»
  возвращает признак
  разбор дерева
    случай Лист
      то да
    случай вариант Узел с левое как л и правое как п
      если («Сбалансировано» от л) равен нет
        то нет
        иначе
          если («Сбалансировано» от п) равен нет
            то нет
            иначе
              пусть разница равно («Глубина» от л) минус («Глубина» от п)
              если разница меньше 0
                то (0 минус разница) не больше 1
                иначе разница не больше 1

тотальная функция «Сбалансировано для списка»
  принимает элементы: список числа
  возвращает признак
  пример «Сбалансированное дерево»
    дано элементы равно [2, 1, 3]
    ожидается да
  пример «Цепочка не сбалансирована»
    дано элементы равно [1, 2, 3, 4]
    ожидается нет
  пример «Пустое дерево сбалансировано»
    дано элементы равно пустой список
    ожидается да
  «Сбалансировано» от («Дерево из списка» от элементы)
121 Лучшая сделка Best Time to Buy and Sell Stock завершение доказано динамика 3/3 примеров 1/1 функций тотальны 36 строк

Один проход свёрткой, состояние — запись «минимальная цена, лучшая прибыль».

flang check
модуль «Лучшая сделка» проходит проверку типов, объявлено типов: 1. Главная функция «Лучшая прибыль» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Лучшая прибыльтотальная
examples/flang/leetcode/121-best-time-to-buy-and-sell-stock.flang2118 байт · sha256 0cdee4c952c344b5
модуль «Лучшая сделка»

// LeetCode 121. Best Time to Buy and Sell Stock.
// По списку цен по дням найти наибольшую прибыль от одной покупки и одной
// последующей продажи. Если прибыли нет — ноль.
//
// Тотальная: один проход свёрткой, состояние — запись из двух чисел
// (минимальная цена и лучшая прибыль).

объект «Сделка»
  минимум является числом
  прибыль является числом

тотальная функция «Лучшая прибыль»
  принимает цены: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано цены равно [7, 1, 5, 3, 6, 4]
    ожидается 5
  пример «Пример 2 из условия»
    дано цены равно [7, 6, 4, 3, 1]
    ожидается 0
  пример «Пустой список»
    дано цены равно пустой список
    ожидается 0
  разбор цены
    случай пусто
      то 0
    случай голова и хвост
      пусть начальное равно запись «Сделка» с минимум равным голова и прибыль равным 0
      пусть итог равно свёртка хвост начиная с начальное как акк и цена
        пусть минимум равно если цена меньше акк.минимум то цена иначе акк.минимум
        пусть сегодня равно цена минус акк.минимум
        пусть прибыль равно если сегодня больше акк.прибыль то сегодня иначе акк.прибыль
        запись «Сделка» с минимум равным минимум и прибыль равным прибыль
      итог.прибыль
125 Палиндром Valid Palindrome доказательства нет строки 12/12 примеров 3/7 функций тотальны 98 строк

Нижний регистр — таблицей из двух алфавитов: встроенной формы «код символа» нет. Нетотальна из-за обхода символов; кириллица решением не покрыта.

flang check
модуль «Палиндром» проходит проверку типов. Главная функция «Палиндром» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
12 примеров в файле, сошлось 12, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать строку в началототальная
  • Позиция подстрокитотальная
  • Значащий символтотальная
  • Символы с позициибез доказательства
  • Очиститьбез доказательства
  • Обратить строкубез доказательства
  • Палиндромбез доказательства
examples/flang/leetcode/125-valid-palindrome.flang5382 байт · sha256 32d4e4edd19b9034
модуль «Палиндром»

// LeetCode 125. Valid Palindrome.
// Строка считается палиндромом, если после выбрасывания всего, кроме букв и
// цифр, и приведения к нижнему регистру она читается одинаково в обе стороны.
//
// Обычная. Причина та же, что у остальных строковых задач: чтобы пройти по
// символам, нужна рекурсия по строке, а её анализ завершаемости не признаёт.
// Заметно и второе ограничение: нижний регистр приходится делать таблицей
// из двух алфавитов — встроенной формы «код символа» в языке нет, поэтому
// связать «A» и «a» иначе нечем. Кириллица этим решением не покрыта.

тотальная функция «Приписать строку в начало»
  принимает первая: строка, элементы: список строки
  возвращает список строки
  пример «В непустой»
    дано первая равно "a"
    дано элементы равно ["b"]
    ожидается ["a", "b"]
  свёртка элементы начиная с [первая] как акк и эл → добавить эл к акк

тотальная функция «Позиция подстроки»
  принимает текст: строка, часть: строка
  возвращает число
  пример «В середине»
    дано текст равно "abcd"
    дано часть равно "c"
    ожидается 3
  пример «Нет вхождения»
    дано текст равно "abc"
    дано часть равно "z"
    ожидается 0
  если текст содержит часть
    то (длина (голова (разделить текст по часть))) плюс 1
    иначе 0

тотальная функция «Значащий символ»
  принимает буква: строка
  возвращает строка
  пример «Заглавная становится строчной»
    дано буква равно "P"
    ожидается "p"
  пример «Цифра остаётся»
    дано буква равно "7"
    ожидается "7"
  пример «Знак препинания выбрасывается»
    дано буква равно ","
    ожидается ""
  пусть позиция равно «Позиция подстроки» от "ABCDEFGHIJKLMNOPQRSTUVWXYZ" и буква
  если позиция больше 0
    то подстрока "abcdefghijklmnopqrstuvwxyz" с позиция по позиция
    иначе
      если "abcdefghijklmnopqrstuvwxyz0123456789" содержит буква то буква иначе ""

функция «Символы с позиции»
  принимает текст: строка, позиция: число
  возвращает список строки
  пример «С последнего символа»
    дано текст равно "ab"
    дано позиция равно 2
    ожидается ["b"]
  если позиция больше (длина текст)
    то пустой список
    иначе
      пусть буква равно подстрока текст с позиция по позиция
      «Приписать строку в начало» от буква и («Символы с позиции» от текст и (позиция плюс 1))

функция «Очистить»
  принимает текст: строка
  возвращает строка
  пример «Знаки и регистр»
    дано текст равно "A man, a plan"
    ожидается "amanaplan"
  свёртка («Символы с позиции» от текст и 1) начиная с "" как акк и буква
    соединить акк с («Значащий символ» от буква)

функция «Обратить строку»
  принимает текст: строка
  возвращает строка
  пример «Слово»
    дано текст равно "abc"
    ожидается "cba"
  свёртка («Символы с позиции» от текст и 1) начиная с "" как акк и буква → соединить буква с акк

функция «Палиндром»
  принимает текст: строка
  возвращает признак
  пример «Пример 1 из условия»
    дано текст равно "A man, a plan, a canal: Panama"
    ожидается да
  пример «Пример 2 из условия»
    дано текст равно "race a car"
    ожидается нет
  пример «Пример 3 из условия»
    дано текст равно " "
    ожидается да
  пусть чистое равно «Очистить» от текст
  чистое равен («Обратить строку» от чистое)
136 Одиночное число Single Number завершение доказано списки 4/4 примеров 2/2 функций тотальны 36 строк

Побитового исключающего ИЛИ в языке нет вовсе, поэтому подсчёт вхождений: O(n²) вместо O(n).

flang check
модуль «Одиночное число» проходит проверку типов. Главная функция «Одиночное число» тотальна: компилятор принял доказательство завершения.
flang test
4 примеров в файле, сошлось 4, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Считать вхождениятотальная
  • Одиночное числототальная
examples/flang/leetcode/136-single-number.flang2013 байт · sha256 81a03d914c827526
модуль «Одиночное число»

// LeetCode 136. Single Number.
// В списке каждое число встречается дважды, кроме одного. Найти его.
//
// Тотальная. Канонического решения «сложить всё исключающим ИЛИ» здесь нет:
// побитовых операций в языке нет вообще (SPEC, раздел 4 перечисляет только
// арифметику и сравнения). Поэтому — подсчёт вхождений, O(n²) вместо O(n).

тотальная функция «Считать вхождения»
  принимает элементы: список числа, значение: число
  возвращает число
  пример «Два вхождения»
    дано элементы равно [4, 1, 4]
    дано значение равно 4
    ожидается 2
  свёртка элементы начиная с 0 как акк и эл → если эл равен значение то акк плюс 1 иначе акк

тотальная функция «Одиночное число»
  принимает элементы: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [2, 2, 1]
    ожидается 1
  пример «Пример 2 из условия»
    дано элементы равно [4, 1, 2, 1, 2]
    ожидается 4
  пример «Пример 3 из условия»
    дано элементы равно [1]
    ожидается 1
  пусть одиночные равно отфильтровать элементы где эл → («Считать вхождения» от элементы и эл) равен 1
  разбор одиночные
    случай пусто
      то 0
    случай голова и хвост
      голова
169 Мажоритарный элемент Majority Element завершение доказано списки 3/3 примеров 2/2 функций тотальны 34 строк

Прямой подсчёт вхождений и фильтр. Бойер — Мур без изменяемых счётчиков всё равно свёлся бы к свёртке с записью.

flang check
модуль «Мажоритарный элемент» проходит проверку типов. Главная функция «Мажоритарный элемент» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Считать вхождениятотальная
  • Мажоритарный элементтотальная
examples/flang/leetcode/169-majority-element.flang1974 байт · sha256 8b6fd2c62b01052f
модуль «Мажоритарный элемент»

// LeetCode 169. Majority Element.
// Найти элемент, встречающийся более чем в половине позиций списка.
//
// Тотальная. Алгоритм Бойера — Мура здесь не нужен: без изменяемых счётчиков
// он всё равно свёлся бы к свёртке с записью-состоянием, а прямой подсчёт
// вхождений короче и очевидно верен. Цена — O(n²).

тотальная функция «Считать вхождения»
  принимает элементы: список числа, значение: число
  возвращает число
  пример «Три тройки»
    дано элементы равно [3, 3, 3, 1]
    дано значение равно 3
    ожидается 3
  свёртка элементы начиная с 0 как акк и эл → если эл равен значение то акк плюс 1 иначе акк

тотальная функция «Мажоритарный элемент»
  принимает элементы: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [3, 2, 3]
    ожидается 3
  пример «Пример 2 из условия»
    дано элементы равно [2, 2, 1, 1, 1, 2, 2]
    ожидается 2
  пусть половина равно (длина элементы) делить на 2
  пусть частые равно отфильтровать элементы где эл → («Считать вхождения» от элементы и эл) больше половина
  разбор частые
    случай пусто
      то 0
    случай голова и хвост
      голова
217 Есть повторы Contains Duplicate завершение доказано списки 3/3 примеров 1/1 функций тотальны 26 строк

Рекурсия по хвосту плюс «хвост содержит голову». Множеств нет, отсюда O(n²).

flang check
модуль «Есть повторы» проходит проверку типов. Главная функция «Есть повторы» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Есть повторытотальная
examples/flang/leetcode/217-contains-duplicate.flang1340 байт · sha256 2c175e173292198d
модуль «Есть повторы»

// LeetCode 217. Contains Duplicate.
// Есть ли в списке хотя бы одно значение, встречающееся дважды.
//
// Тотальная: рекурсия строго по хвосту списка. Множества в языке нет,
// поэтому проверка «голова встречается дальше» — линейный поиск,
// и всё решение получается O(n²).

тотальная функция «Есть повторы»
  принимает элементы: список числа
  возвращает признак
  пример «Пример 1 из условия»
    дано элементы равно [1, 2, 3, 1]
    ожидается да
  пример «Пример 2 из условия»
    дано элементы равно [1, 2, 3, 4]
    ожидается нет
  пример «Пример 3 из условия»
    дано элементы равно [1, 1, 1, 3, 3, 4, 3, 2, 4, 2]
    ожидается да
  разбор элементов
    случай пусто
      то нет
    случай голова и хвост
      если хвост содержит голова то да иначе «Есть повторы» от хвоста
226 Развернуть дерево Invert Binary Tree завершение доказано деревья 5/5 примеров 7/7 функций тотальны 88 строк

Само «Развернуть» примера иметь не может — оно возвращает вариант. Проверяется наблюдаемое следствие: обход по порядку до и после разворота.

flang check
модуль «Развернуть дерево» проходит проверку типов, объявлено типов: 1. Главная функция «Обход после разворота» тотальна: компилятор принял доказательство завершения.
flang test
5 примеров в файле, сошлось 5, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Соединить спискитотальная
  • Вставить в деревототальная
  • Дерево из спискатотальная
  • Развернутьтотальная
  • Обход по порядкутотальная
  • Обход дерева из спискатотальная
  • Обход после разворотатотальная
examples/flang/leetcode/226-invert-binary-tree.flang5578 байт · sha256 0e9b6530589aa7e5
модуль «Развернуть дерево»

// LeetCode 226. Invert Binary Tree.
// Поменять местами левое и правое поддерево у каждого узла.
//
// Тотальная. Само «Развернуть» примера иметь не может: оно возвращает
// вариант, а значение варианта в «ожидается» не записывается — парсер
// разворачивает конструктор в запись из его полей и теряет имя варианта.
// Поэтому проверяется наблюдаемое следствие: обход по возрастанию до и после
// разворота. У дерева поиска обход по порядку отсортирован, у развёрнутого —
// отсортирован в обратную сторону.

тип «Дерево»
  вариант Лист
  вариант Узел содержит значение: число, левое: «Дерево», правое: «Дерево»

тотальная функция «Соединить списки»
  принимает первый: список числа, второй: список числа
  возвращает список числа
  пример «Склейка»
    дано первый равно [1]
    дано второй равно [2, 3]
    ожидается [1, 2, 3]
  свёртка второй начиная с первый как акк и эл → добавить эл к акк

тотальная функция «Вставить в дерево»
  принимает дерево: «Дерево», число: число
  возвращает «Дерево»
  разбор дерева
    случай Лист
      то Узел с значение равным число и левое равным вариант Лист и правое равным вариант Лист
    случай вариант Узел с значение как зн и левое как л и правое как п
      если число меньше зн
        то
          пусть новое равно «Вставить в дерево» от л и число
          Узел с значение равным зн и левое равным новое и правое равным п
        иначе
          пусть новое равно «Вставить в дерево» от п и число
          Узел с значение равным зн и левое равным л и правое равным новое

тотальная функция «Дерево из списка»
  принимает элементы: список числа
  возвращает «Дерево»
  свёртка элементы начиная с вариант Лист как акк и эл → «Вставить в дерево» от акк и эл

тотальная функция «Развернуть»
  принимает дерево: «Дерево»
  возвращает «Дерево»
  разбор дерева
    случай Лист
      то вариант Лист
    случай вариант Узел с значение как зн и левое как л и правое как п
      пусть слева равно «Развернуть» от п
      пусть справа равно «Развернуть» от л
      Узел с значение равным зн и левое равным слева и правое равным справа

тотальная функция «Обход по порядку»
  принимает дерево: «Дерево»
  возвращает список числа
  разбор дерева
    случай Лист
      то пустой список
    случай вариант Узел с значение как зн и левое как л и правое как п
      пусть слева равно «Обход по порядку» от л
      пусть справа равно «Обход по порядку» от п
      «Соединить списки» от (добавить зн к слева) и справа

тотальная функция «Обход дерева из списка»
  принимает элементы: список числа
  возвращает список числа
  пример «Дерево поиска обходится по возрастанию»
    дано элементы равно [4, 2, 7, 1, 3, 6, 9]
    ожидается [1, 2, 3, 4, 6, 7, 9]
  «Обход по порядку» от («Дерево из списка» от элементы)

тотальная функция «Обход после разворота»
  принимает элементы: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано элементы равно [4, 2, 7, 1, 3, 6, 9]
    ожидается [9, 7, 6, 4, 3, 2, 1]
  пример «Пример 2 из условия»
    дано элементы равно [2, 1, 3]
    ожидается [3, 2, 1]
  пример «Пустое дерево»
    дано элементы равно пустой список
    ожидается пустой список
  «Обход по порядку» от («Развернуть» от («Дерево из списка» от элементы))
242 Анаграмма Valid Anagram завершение доказано строки 5/5 примеров 2/2 функций тотальны 47 строк

Тотальная задача про строки: счёт буквы = число частей «разделить» минус один, перебор идёт по литеральному алфавиту из 26 букв, а не по символам слова.

flang check
модуль «Анаграмма» проходит проверку типов. Главная функция «Анаграмма» тотальна: компилятор принял доказательство завершения.
flang test
5 примеров в файле, сошлось 5, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Счёт буквытотальная
  • Анаграмматотальная
examples/flang/leetcode/242-valid-anagram.flang2622 байт · sha256 af1a5f7701a87e60
модуль «Анаграмма»

// LeetCode 242. Valid Anagram.
// Проверить, что второе слово — перестановка первого. По условию буквы
// только строчные латинские.
//
// Тотальная — и это неожиданно, потому что задача про строки. Приём:
// считать буквы не обходом строки, а встроенной «разделить». Число вхождений
// буквы равно числу частей минус один, а перебирать надо не символы слова,
// а заранее известный алфавит из 26 букв — конечный список, записанный
// литералом. Свёртка по литеральному списку тотальна всегда.

тотальная функция «Счёт буквы»
  принимает текст: строка, буква: строка
  возвращает число
  пример «Две буквы a»
    дано текст равно "abac"
    дано буква равно "a"
    ожидается 2
  пример «Буквы нет»
    дано текст равно "bbb"
    дано буква равно "a"
    ожидается 0
  (длина (разделить текст по буква)) минус 1

тотальная функция «Анаграмма»
  принимает первое: строка, второе: строка
  возвращает признак
  пример «Пример 1 из условия»
    дано первое равно "anagram"
    дано второе равно "nagaram"
    ожидается да
  пример «Пример 2 из условия»
    дано первое равно "rat"
    дано второе равно "car"
    ожидается нет
  пример «Разная длина»
    дано первое равно "a"
    дано второе равно "ab"
    ожидается нет
  если (длина первое) не равен (длина второе)
    то нет
    иначе
      свёртка ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] начиная с да как акк и буква
        если акк равен нет
          то нет
          иначе («Счёт буквы» от первое и буква) равен («Счёт буквы» от второе и буква)
268 Пропущенное число Missing Number завершение доказано числа 4/4 примеров 2/2 функций тотальны 32 строк

Сумма прогрессии минус сумма списка. Единственная задача набора, где язык не мешает ничем.

flang check
модуль «Пропущенное число» проходит проверку типов. Главная функция «Пропущенное число» тотальна: компилятор принял доказательство завершения.
flang test
4 примеров в файле, сошлось 4, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Сумматотальная
  • Пропущенное числототальная
examples/flang/leetcode/268-missing-number.flang1703 байт · sha256 d3b27a7b0110e525
модуль «Пропущенное число»

// LeetCode 268. Missing Number.
// В списке лежат все числа от 0 до n, кроме одного. Найти пропущенное.
//
// Тотальная и без рекурсии: сумма арифметической прогрессии минус сумма
// списка. Здесь язык не мешает вовсе — вся задача выражается двумя свёртками
// и арифметикой.

тотальная функция «Сумма»
  принимает элементы: список числа
  возвращает число
  пример «Сумма трёх»
    дано элементы равно [1, 2, 3]
    ожидается 6
  свёртка элементы начиная с 0 как акк и эл → акк плюс эл

тотальная функция «Пропущенное число»
  принимает элементы: список числа
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [3, 0, 1]
    ожидается 2
  пример «Пример 2 из условия»
    дано элементы равно [0, 1]
    ожидается 2
  пример «Пример 3 из условия»
    дано элементы равно [9, 6, 4, 2, 3, 5, 7, 0, 1]
    ожидается 8
  пусть предел равно длина элементы
  пусть полная равно (предел умножить на (предел плюс 1)) делить на 2
  полная минус («Сумма» от элементы)
283 Сдвинуть нули Move Zeroes завершение доказано списки 3/3 примеров 2/2 функций тотальны 30 строк

Два фильтра и склейка, без рекурсии. «На месте» не выражается: значения неизменяемы.

flang check
модуль «Сдвинуть нули» проходит проверку типов. Главная функция «Сдвинуть нули» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Соединить спискитотальная
  • Сдвинуть нулитотальная
examples/flang/leetcode/283-move-zeroes.flang1765 байт · sha256 cea31b85798acb39
модуль «Сдвинуть нули»

// LeetCode 283. Move Zeroes.
// Перенести все нули в конец, сохранив порядок остальных.
//
// Тотальная и без единой рекурсии: два фильтра и склейка. В условии просят
// работать «на месте», но изменяемых массивов в языке нет — возвращается
// новый список того же содержания.

тотальная функция «Соединить списки»
  принимает первый: список числа, второй: список числа
  возвращает список числа
  пример «Склейка»
    дано первый равно [1]
    дано второй равно [0, 0]
    ожидается [1, 0, 0]
  свёртка второй начиная с первый как акк и эл → добавить эл к акк

тотальная функция «Сдвинуть нули»
  принимает элементы: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано элементы равно [0, 1, 0, 3, 12]
    ожидается [1, 3, 12, 0, 0]
  пример «Пример 2 из условия»
    дано элементы равно [0]
    ожидается [0]
  пусть ненулевые равно отфильтровать элементы где эл → эл не равен 0
  пусть нули равно отфильтровать элементы где эл → эл равен 0
  «Соединить списки» от ненулевые и нули
344 Обратить строку Reverse String завершение доказано списки 5/5 примеров 3/3 функций тотальны 41 строк

Условие даёт массив символов — то есть список, а список разбирается структурно. Та же операция над строкой тотальной быть не может.

flang check
модуль «Обратить строку» проходит проверку типов. Главная функция «Обратить символы» тотальна: компилятор принял доказательство завершения.
flang test
5 примеров в файле, сошлось 5, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Приписать строку в началототальная
  • Обратить символытотальная
  • Строка из символовтотальная
examples/flang/leetcode/344-reverse-string.flang2658 байт · sha256 ae630ae685dd937a
модуль «Обратить строку»

// LeetCode 344. Reverse String.
// Условие даёт массив символов и просит обратить его на месте. Массив
// символов — это список строки, и здесь это удача: список flang разбирается
// структурно, а строка нет. Поэтому задача остаётся тотальной, тогда как
// та же операция над строкой (модуль stdlib/strings.flang) тотальной быть
// не может — по строке нельзя рекурсировать с доказательством убывания.
//
// Изменения на месте нет и не будет: значения flang неизменяемы.

тотальная функция «Приписать строку в начало»
  принимает первая: строка, элементы: список строки
  возвращает список строки
  пример «В непустой»
    дано первая равно "а"
    дано элементы равно ["б"]
    ожидается ["а", "б"]
  свёртка элементы начиная с [первая] как акк и эл → добавить эл к акк

тотальная функция «Обратить символы»
  принимает символы: список строки
  возвращает список строки
  пример «Пример 1 из условия»
    дано символы равно ["h", "e", "l", "l", "o"]
    ожидается ["o", "l", "l", "e", "h"]
  пример «Пример 2 из условия»
    дано символы равно ["H", "a", "n", "n", "a", "h"]
    ожидается ["h", "a", "n", "n", "a", "H"]
  пример «Пустой список»
    дано символы равно пустой список
    ожидается пустой список
  свёртка символы начиная с пустой список как акк и буква → «Приписать строку в начало» от буква и акк

тотальная функция «Строка из символов»
  принимает символы: список строки
  возвращает строка
  пример «Склейка»
    дано символы равно ["o", "l", "l", "e", "h"]
    ожидается "olleh"
  свёртка символы начиная с "" как акк и буква → соединить акк с буква
349 Пересечение списков Intersection of Two Arrays завершение доказано списки 3/3 примеров 2/2 функций тотальны 29 строк

Уникальные из первого, фильтр по вхождению во второй. Множеств нет, уникальность строится вручную.

flang check
модуль «Пересечение списков» проходит проверку типов. Главная функция «Пересечение» тотальна: компилятор принял доказательство завершения.
flang test
3 примеров в файле, сошлось 3, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Уникальныетотальная
  • Пересечениетотальная
examples/flang/leetcode/349-intersection-of-two-arrays.flang1642 байт · sha256 5523a0c8114257ab
модуль «Пересечение списков»

// LeetCode 349. Intersection of Two Arrays.
// Вернуть уникальные значения, встречающиеся в обоих списках.
//
// Тотальная: два прохода свёрткой и фильтром, рекурсии нет.
// Множеств в языке нет, «уникальность» строится вручную через «содержит».

тотальная функция «Уникальные»
  принимает элементы: список числа
  возвращает список числа
  пример «С повторами»
    дано элементы равно [1, 1, 2]
    ожидается [1, 2]
  свёртка элементы начиная с пустой список как акк и эл
    если акк содержит эл то акк иначе добавить эл к акк

тотальная функция «Пересечение»
  принимает первый: список числа, второй: список числа
  возвращает список числа
  пример «Пример 1 из условия»
    дано первый равно [1, 2, 2, 1]
    дано второй равно [2, 2]
    ожидается [2]
  пример «Пример 2 из условия»
    дано первый равно [4, 9, 5]
    дано второй равно [9, 4, 9, 8, 4]
    ожидается [4, 9]
  отфильтровать («Уникальные» от первый) где эл → второй содержит эл
509 Фибоначчи Fibonacci Number доказательства нет числа 6/6 примеров 0/2 функций тотальны 42 строк

Линейный вариант с двумя накопителями. Нетотальна ровно из-за счётчика: убывания по числу анализ не знает.

flang check
модуль «Фибоначчи» проходит проверку типов. Главная функция «Фибоначчи» не тотальна: убывание не доказано, конечность держится на входных данных.
flang test
6 примеров в файле, сошлось 6, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Фибоначчи шагомбез доказательства
  • Фибоначчибез доказательства
examples/flang/leetcode/509-fibonacci-number.flang2067 байт · sha256 f097f2cbd55895fe
модуль «Фибоначчи»

// LeetCode 509. Fibonacci Number.
// F(0) = 0, F(1) = 1, дальше сумма двух предыдущих.
//
// Обычная. Прямое определение F(n) = F(n−1) + F(n−2) не проходит анализ
// завершаемости по той же причине, что и всё остальное на числах: убывания
// по числовому аргументу он не знает. Здесь взят линейный вариант с двумя
// накопителями — он и работает быстрее, и делает нетотальность заметной:
// единственное, что мешает доказать конец, — счётчик.

функция «Фибоначчи шагом»
  принимает осталось: число, предыдущее: число, текущее: число
  возвращает число
  пример «Ноль шагов»
    дано осталось равно 0
    дано предыдущее равно 7
    дано текущее равно 9
    ожидается 7
  если осталось не больше 0
    то предыдущее
    иначе «Фибоначчи шагом» от (осталось минус 1) и текущее и (предыдущее плюс текущее)

функция «Фибоначчи»
  принимает н: число
  возвращает число
  пример «Пример 1 из условия»
    дано н равно 2
    ожидается 1
  пример «Пример 2 из условия»
    дано н равно 3
    ожидается 2
  пример «Пример 3 из условия»
    дано н равно 4
    ожидается 3
  пример «Нулевое»
    дано н равно 0
    ожидается 0
  пример «Тридцатое»
    дано н равно 30
    ожидается 832040
  «Фибоначчи шагом» от н и 0 и 1
704 Двоичный поиск Binary Search завершение доказано поиск 5/5 примеров 3/3 функций тотальны 75 строк

Приём «топливо»: рядом с настоящими аргументами едет список, у которого на каждом шаге берётся хвост. Топливо убывает структурно, значит цикл доказуемо конечен.

flang check
модуль «Двоичный поиск» проходит проверку типов. Главная функция «Двоичный поиск» тотальна: компилятор принял доказательство завершения.
flang test
5 примеров в файле, сошлось 5, разошлось 0. Примеры — часть исходника, а не отдельный тестовый файл.
  • Элементтотальная
  • Поиск в диапазонетотальная
  • Двоичный поисктотальная
examples/flang/leetcode/704-binary-search.flang4309 байт · sha256 631cb89f7a5336ab
модуль «Двоичный поиск»

// LeetCode 704. Binary Search.
// В отсортированном списке найти номер цели (с нуля) или −1.
//
// Тотальная — но приёмом, который стоит запомнить, потому что он показывает
// границу анализа завершаемости. Двоичный поиск сужает пару чисел «низ» и
// «верх», а убывание по числам totality.mjs не признаёт: «середина плюс 1» —
// результат арифметики, а не часть значения. Прямая запись даёт
// FLANG_NOT_TOTAL.
//
// Обход: рядом с настоящими аргументами едет «топливо» — список, у которого
// на каждом шаге берётся хвост. Топливо убывает структурно, значит цикл
// доказуемо конечен; а поскольку топливом служит сам список, шагов заведомо
// хватает (их нужно log₂n, а есть n). Приём честный, но это именно приём:
// в языке не хватает убывания по мере.

тотальная функция «Элемент»
  принимает элементы: список числа, номер: число
  возвращает число
  пример «Второй элемент»
    дано элементы равно [10, 20, 30]
    дано номер равно 2
    ожидается 20
  разбор элементов
    случай пусто
      то 0
    случай голова и хвост
      если номер не больше 1
        то голова
        иначе «Элемент» от хвост и (номер минус 1)

тотальная функция «Поиск в диапазоне»
  принимает топливо: список числа, элементы: список числа, цель: число, низ: число, верх: число
  возвращает число
  пример «Нашли середину»
    дано топливо равно [1, 2, 3]
    дано элементы равно [1, 2, 3]
    дано цель равно 2
    дано низ равно 1
    дано верх равно 3
    ожидается 1
  разбор топливо
    случай пусто
      то -1
    случай голова и хвост
      если низ больше верх
        то -1
        иначе
          пусть сумма равно низ плюс верх
          пусть середина равно (сумма минус (сумма остаток от 2)) делить на 2
          пусть значение равно «Элемент» от элементы и середина
          если значение равен цель
            то середина минус 1
            иначе
              если значение меньше цель
                то «Поиск в диапазоне» от хвост и элементы и цель и (середина плюс 1) и верх
                иначе «Поиск в диапазоне» от хвост и элементы и цель и низ и (середина минус 1)

тотальная функция «Двоичный поиск»
  принимает элементы: список числа, цель: число
  возвращает число
  пример «Пример 1 из условия»
    дано элементы равно [-1, 0, 3, 5, 9, 12]
    дано цель равно 9
    ожидается 4
  пример «Пример 2 из условия»
    дано элементы равно [-1, 0, 3, 5, 9, 12]
    дано цель равно 2
    ожидается -1
  пример «Один элемент»
    дано элементы равно [5]
    дано цель равно 5
    ожидается 0
  «Поиск в диапазоне» от элементы и элементы и цель и 1 и (длина элементы)

Граница честности

12 задач в языке не выражаются — и это тоже результат проверки.

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

3Longest Substring Without Repeating Characters

Скользящее окно по строке: две границы, двигающиеся по числовым индексам, и множество символов в окне. Ни окна, ни множества, ни убывания по индексам язык не даёт; выразимо лишь квадратичным перебором подстрок в обычном классе, что уже не решение задачи.

разложение строкиубывание по меремножество
4Median of Two Sorted Arrays

Требуемое O(log(m+n)) — двоичный поиск по разделяющей позиции сразу в двух массивах с произвольным доступом. Индексный доступ в flang линеен, поэтому даже правильный алгоритм даст O(n log n), а тотальность потребует топлива для каждого из двух поисков.

массив с индексным доступомубывание по мере
23Merge k Sorted Lists

Сам результат выразим (свёртка слиянием), но условие говорит о связных списках и требует O(N log k) через кучу. Связный список в flang неотличим от обычного списка, а куча требует индексного доступа. Задача в её настоящей формулировке отсутствует в языке вместе со структурой данных.

массив с индексным доступомссылочные структуры
76Minimum Window Substring

Скользящее окно плюс счётчики символов в словаре. Ни того, ни другого; перебор всех подстрок требует обхода строки по двум индексам — нетотально и за пределами разумного лимита шагов.

разложение строкиассоциативный массивубывание по мере
139Word Break

Нужны и разрезы строки по всем позициям (обход строки), и запоминание уже посчитанных суффиксов. Первого нет тотально, второго нет никак: мемоизация — это состояние.

разложение строкимемоизация
146LRU Cache

Требуется объект с состоянием и набором методов (get/put), сохраняющий его между вызовами. В flang нет ни изменяемых значений, ни объектов с методами, ни способа завести долгоживущее состояние: функция — чистое отображение аргументов в результат.

изменяемое состояниеобъекты с методамиассоциативный массив
155Min Stack

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

изменяемое состояниеобъекты с методами
179Largest Number

Сортировка строк по правилу «a+b против b+a». Сравнивать строки в flang нельзя вообще: types.mjs считает строки упорядоченными, а интерпретатор на «больше»/«меньше» для строк бросает FLANG_TYPE («сравнения порядка допустимы только для чисел»). Обойти это можно только собственной посимвольной функцией сравнения — то есть нетотально и через несуществующее разложение строки.

сравнение строкразложение строки
200Number of Islands

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

изменяемое состояниемассив с индексным доступомубывание по мере
208Implement Trie

Опять API с состоянием; кроме того, узел бора — это словарь «символ → узел», а ассоциативных массивов нет. Список пар с линейным поиском превращает O(длины слова) в O(длины × алфавит) и перестаёт быть бором по существу.

изменяемое состояниеассоциативный массив
295Find Median from Data Stream

Поток и две кучи: и то, и другое — состояние, живущее между вызовами. Куча к тому же требует индексного доступа к массиву, которого в языке нет (только «голова», «хвост» и обход).

изменяемое состояниемассив с индексным доступом
322Coin Change

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

массив с индексным доступомубывание по меремемоизация
Чего не хватает языку: 16 пунктов из разбора этих решений
разложение строки
Нет встроенной формы «символы строки» и нет образцов для строк: «пусто» и «голова и хвост» работают только со списком. Любой посимвольный проход — обычная функция. Это самая дорогая из недостач: она одна делает нетотальными задачи 13, 14, 20, 125.
убывание по мере
Анализ завершаемости знает только структурное убывание. Рекурсия «n минус 1», Евклид, двоичный поиск по границам — всё это FLANG_NOT_TOTAL, хотя завершается очевидно. Обход есть (список-топливо), но он засоряет сигнатуру.
ассоциативный массив
Нет ни словаря, ни множества. Каждая задача «посчитай, сколько раз встретилось» превращается из O(n) в O(n²): 1, 136, 169, 217, 49.
массив с индексным доступом
Список читается только с головы; «Элемент по номеру» пишется рекурсией и стоит O(n). Кучи, таблицы динамики и двумерные сетки на этом ломаются.
сравнение строк
types.mjs разрешает «больше»/«меньше» для строк, а interpret.mjs на них бросает FLANG_TYPE. Это расхождение слоёв: программа проходит проверку и падает при запуске. Сортировка строк невыразима.
логические операции
Нет «и», «или», «не» для признаков. Конъюнкция пишется вложенными «если», отрицание — сравнением «равен нет». Читается заметно хуже написанного условия.
параметрический полиморфизм
«Обратить» для списка числа и для списка строки — две разные функции с одинаковым телом. Опциональное значение приходится заводить отдельно под каждый тип, а имена вариантов обязаны быть уникальны в модуле.
модульность
Заголовок «модуль … использует …» разбирается, но связывания между файлами нет: каждое решение переписывает нужные ему «Приписать в начало» и «Соединить списки» заново. Стандартной библиотекой нельзя воспользоваться из решения.
значение варианта в примере
parseLiteralValue сворачивает конструктор варианта в запись из его полей и теряет имя варианта. Поэтому функция, принимающая или возвращающая сумму типов, примера иметь не может — приходится обкладывать её скалярными обёртками.
структурное сравнение в примерах
runExamples (compat.mjs) сравнивает результат с ожидаемым через Object.is, поэтому любой пример, возвращающий список или запись, считается провалившимся, даже когда значения совпадают поэлементно. Команда «flang test» на таких файлах не работает; тесты в flang/test сравнивают структурно (valuesEqual) и проходят.
встроенная форма «символ»
Парсер и builtins.mjs передают «символ N в текст» как (число, строка), а types.mjs ждёт (строка, число). Любое использование формы «символ» не проходит check; вместо неё приходится писать «подстрока текст с N по N».
встроенная форма «пусто»
В позиции выражения слово «пусто» всегда читается как литерал пустого списка, поэтому до одноимённой встроенной формы (проверка «список или строка пусты») из исходника не добраться. Пишется «(длина x) равен 0».
списочная форма «соединить»
builtins.mjs умеет «соединить список с разделителем», но поверхностный синтаксис «соединить X с Y» всегда даёт склейку двух строк. Соединение списка строк написано в stdlib заново.
вызов функции без аргументов
Применение записывается только как «Имя» от аргумента, поэтому функцию с пустым списком параметров вызвать нечем. Константы приходится делать функциями от неиспользуемого аргумента или встраивать выражением.
псевдоним типа
«тип «X» это список числа» разбирается в узел alias, но types.mjs раскладывает объявления на суммы и записи, и alias становится записью без полей. Пользоваться псевдонимами нельзя.
обработка ошибок
Отказ встроенной формы («к числу» от «abc», «голова» от пустого списка) прекращает вычисление целиком и не перехватывается. Проверять пригодность аргумента приходится заранее, а выразить эту проверку удаётся не всегда.

Дальше

Тот же компилятор, только на предметных правилах.

flang вырос из FTS — языка исполняемых спецификаций, где то же доказательство завершения работает на скидках, допусках и тарифах. На странице раздела есть песочница, 232 прикладных кейсов и полный курс.