openlang

Для Коллатца честный ответ это partial def

Lean должен знать, что рекурсивный def завершается, прежде чем принять его как определение. Структурную рекурсию он находит сам. Иначе пробует фундированную рекурсию, а вы помогаете ему через termination_by, называя меру, и через decreasing_by, доказывая, что каждый вызов её уменьшает.

Для числа шагов Коллатца известной меры нет. Никто не доказал, что эта функция завершается на любом входе. Поэтому пишем partial def. Lean её компилирует и выполняет. Он требует, чтобы тип результата был населён, а в доказательствах определение непрозрачно. Вычислять можно. Рассуждать о её развёртке нельзя.

Мне этот обмен нравится. Ключевое слово здесь и есть спецификация, которая говорит правду. Тотальный def утверждает, что функция возвращает результат на каждом входе, и проверка заставляет за это отвечать. partial ничего такого не утверждает.

Любая проверка, которая всегда даёт ответ, обязана отвергать и некоторые завершающиеся функции. Пусть. Цена отказа одно честное ключевое слово, а программа всё равно работает.

Разговор продолжается 4

Следуя доводам
  1. Ссылка на ответ

    В Idris 2 есть третья метка, и я пользуюсь ею чаще всего. total соответствует вашему честному def, partial соответствует partial def. Между ними стоит covering. Для каждого входа есть подходящая клауза, но завершение не обещано. Для числа шагов Коллатца это полезное утверждение, потому что меня на практике подводит пропущенный случай, а не зацикливание. А %default total в начале файла переворачивает бремя для всего остального, что удобно, когда модуль почти целиком арифметика.

  2. Ссылка на ответ

    Простая стрелка утверждает меньше, чем covering. В OCaml тип той же функции int -> int, и let rec принимается, что бы он ни делал во время выполнения. Такой тип даже не обещает, что разобраны все образцы, потому что неполное сопоставление даёт лишь предупреждение. Меньшее утверждение допустимо, если никто не вычитывает из стрелки больше, чем в ней написано.

  3. Ссылка на ответ

    Здесь полезно различать два вида программ. Число шагов Коллатца должно вернуть число, и вопрос о завершении уместен. Цикл чтения и вычисления или сервер не должен возвращаться никогда, и нужное свойство другое. Каждый оборот цикла завершается, а сам цикл работает в постоянной памяти.

    R7RS обеспечивает второе одним правилом. Раздел 3.5 требует корректной хвостовой рекурсии, поэтому процедура, вызывающая себя в хвостовой позиции, и есть цикл, без роста стека и без особого синтаксиса. Вот почему в учебном Scheme сервер можно показать пятью строками обычной рекурсии.

    Проверке тотальности об этом цикле сказать нечего. partial тоже молчит. Недостающее слово здесь продуктивность.

Другие стороны того же вопроса

  1. Исчерпанный бюджет поиска не означает отсутствия ответа

    let loop = loop in if loop then Just 1 else Nothing имеет тип Maybe Int, но это ни Just, ни Nothing. Чтобы различить их, вызы…

    Ответы 1haskell