Я не могу доказать (n - 0) = n с Idris

Я пытаюсь доказать, что, на мой взгляд, разумная теорема:

theorem1 : (n : Nat) -> (m : Nat) -> (n + (m - n)) = m

Доказательство по индукции доходит до той точки, где мне нужно это доказать:

lemma1 : (n : Nat) -> (n - 0) = n

Это то, что происходит, когда я пытаюсь это доказать (лемма, для простоты) с использованием интерактивного метода:

----------                 Goal:                  ----------
{hole0} : (n : Nat) -> minus n 0 = n

> intros
----------              Other goals:              ----------
{hole0}
----------              Assumptions:              ----------
 n : Nat
----------                 Goal:                  ----------
{hole1} : minus n 0 = n

> trivial
Can't unify
        n = n
with
        minus n 0 = n

Specifically:
        Can't unify
                n
        with
                minus n 0

Мне казалось, что я должен что-то пропустить в определении минуса, поэтому я посмотрел его в источнике:

||| Subtract natural numbers. If the second number is larger than the first, return 0.
total minus : Nat -> Nat -> Nat
minus Z        right     = Z
minus left     Z         = left
minus (S left) (S right) = minus left right

Определение, в котором я нуждаюсь, прямо здесь! minus left Z = left. Я понял, что Идрис должен просто заменить minus m 0 на m здесь, и это тогда рефлексивно верно. Что я пропустил?

Ответы

Ответ 1

К сожалению, теорема, которую вы хотите доказать здесь, на самом деле не верна, потому что Idris naturals обрезает вычитание в 0. Контрпример к вашему theorem1 составляет n=3, m=0. Позвольте пройти оценку:

Сначала подставим:

3 + (0 - 3) = 0

Затем мы отменим синтаксис основного экземпляра Num и поместим в вызываемые функции:

plus (S (S (S Z))) (minus Z (S (S (S Z))))) = Z

Идрис - это строгий язык по умолчанию, поэтому сначала мы оцениваем аргументы функций. Таким образом, мы уменьшаем выражение minus Z (S (S (S Z)))). Рассматривая определение minus, применяется первый шаблон, потому что первый аргумент Z. Итак, мы имеем:

plus (S (S (S Z))) Z = Z

plus является рекурсивным по первому аргументу, поэтому следующий шаг оценки дает:

S (plus (S (S Z)) Z) = Z

Мы продолжаем этот путь до тех пор, пока plus не получит Z в качестве своего первого аргумента, после чего он вернет свой второй аргумент Z, выдав тип:

S (S (S Z)) = Z

для которого мы не можем построить жителя для.

Извините, если выше показалось немного педантичным и низкоуровневым, но очень важно принять конкретные меры по сокращению при работе с зависимыми типами. Это вычисление, которое вы получаете "бесплатно" внутри типов, поэтому хорошо организовать для него удобные результаты.

Решение pdxleif выше хорошо работает для вашей леммы. Случай, разбитый на первый аргумент, был необходим, чтобы получить соответствие шаблону в minus. Помните, что это происходит сверху вниз в совпадениях шаблона, и первый шаблон имеет конкретный конструктор по первому аргументу, а это означает, что сокращение не может продолжаться до тех пор, пока оно не узнает, соответствует ли этот конструктор.

Ответ 2

Просто играя с интерактивным редактированием, разложил случай и проверил поиск, получив:

lemma1 : (n : Nat) -> (n - 0) = n
lemma1 Z = refl
lemma1 (S k) = refl

Это очевидно из определения минуса, поэтому он просто refl. Может быть, это было неприятно, когда вход var был просто n, потому что он мог иметь другое поведение, если это было Z или что-то еще? Или рекурсия?

Ответ 3

На всякий случай, много арифметических лемм уже определено в Прелюдии Идриса, как и ваш:

total minusZeroRight : (left : Nat) -> left - 0 = left
minusZeroRight Z        = refl
minusZeroRight (S left) = refl

Ответ 4

Для полноты (тактический язык устарел в пользу рефлектометра), я добавлю, что способ доказать вашу лемму на тактическом языке - это вызвать induction n. Затем вы можете использовать trivial для отображения каждого случая (после intros в индуктивном случае).

----------                 Goal:                  ----------
{hole0} : (n : Nat) -> minus n 0 = n
-lemma1> intros
----------              Other goals:              ----------
{hole0}
----------              Assumptions:              ----------
 n : Nat
----------                 Goal:                  ----------
{hole1} : minus n 0 = n
-lemma1> induction n
----------              Other goals:              ----------
elim_S0,{hole1},{hole0}
----------              Assumptions:              ----------
 n : Nat
----------                 Goal:                  ----------
elim_Z0 : minus 0 0 = 0
-lemma1> trivial
----------              Other goals:              ----------
{hole1},{hole0}
----------              Assumptions:              ----------
 n : Nat
----------                 Goal:                  ----------
elim_S0 : (n__0 : Nat) ->
          (minus n__0 0 = n__0) -> minus (S n__0) 0 = S n__0
-lemma1> intros
----------              Other goals:              ----------
{hole8},elim_S0,{hole1},{hole0}
----------              Assumptions:              ----------
 n : Nat
 n__0 : Nat
 ihn__0 : minus n__0 0 = n__0
----------                 Goal:                  ----------
{hole9} : minus (S n__0) 0 = S n__0
-lemma1> trivial
lemma1: No more goals.
-lemma1> qed
Proof completed!
lemma1 = proof
  intros
  induction n
  trivial
  intros
  trivial