Когда вы вызываете тактику induction
, Coq использует эвристику для определения предиката P : nat -> Prop
, который вы хотите доказать по индукции. Перед повторным вызовом induction
состояние проверки выглядит следующим образом:
m, n : nat
IHn : m * n = n * m
============================
m * S n = m + m * n
Случилось так, что Кок решил включить предпосылку IHn
в предикат индукции, который был выведен как
P m := m * n = n * m -> m * S n = m + m * n
Это именно то, что вы имели в своей гипотезе индукции. В этом случае вы можете утверждать, что Coq глупо использовать посылку, но есть случаи, когда отбрасывание этого приведет к недоказуемым целям. Например, рассмотрим следующую попытку доказательства:
Lemma double_inj : forall n m, n + n = m + m -> n = m.
Proof.
intros n m H.
induction n as [|n IH].
(* ... *)
Если H
был сброшен после вызова induction
, вам пришлось бы доказать forall n m, n = m
, что явно не выполняется.
Этот пример является одной из причин, почему часто бывает плохой идеей вызывать induction
несколько раз в одном доказательстве Coq. Как мы предлагаем в этом упражнении в Основах программного обеспечения, лучше доказать вспомогательную лемму, поскольку вы можете четко указать предикат индукции. Для этого примера есть и другие варианты. Например, вы можете вызвать clear IHn
, чтобы отбросить предпосылку IHn
, что приведет Coq к правильному предикату. Язык доказательства ssreflect, который теперь поставляется с Coq, имеет другую тактику для выполнения индукции, которая называется elim
, что позволяет вам более четко выбирать предикат.
Я согласен с вашим последним комментарием, но должен добавить, что целью программных фондов не является введение в программирование с зависимой типизацией. Несмотря на то, что Coq поддерживает эту парадигму, писать такие программы обычно непросто, и гораздо проще использовать тактику для доказательства лемм о просто типизированных программах. Например, Idris принимает ваше доказательство mult_comm
, потому что его средство проверки завершения достаточно умен, чтобы распознавать все рекурсивные вызовы как убывающие, даже если они не уменьшаются относительно фиксированного аргумента (во втором предложении n
уменьшается тогда как в третьем m
делает). Это невозможно в Coq, и вы должны разделить определение на несколько рекурсивных функций, по одной для каждого аргумента, или использовать обоснованную индукцию для пар натуральных чисел, что в данном примере было бы излишним.
У Адама Члипалы есть еще один учебник Coq под названием CPDT , который вы, возможно, захотите проверить. Тем не менее, я не думаю, что вы найдете там исчерпывающее описание тактики Coq. Как и induction
, многие тактики основаны на эвристике и их сложно объяснить подробно.
В заключение отметим, что Матье Созо разработал пакет под названием Equations , который делает программирование с зависимой типизацией в Coq намного ближе к Idris или Agda. Если вы находите этот стиль доказательства более интуитивным, вы можете попробовать использовать его.