Хотя то, что сказал Чи, верно, в этом случае вы действительно можете извлечь свидетеля p
из доказательства существования.Если у вас есть логический предикат P : nat -> bool
, если exists p, P p = true
, вы можете вычислить некоторое значение p
, которое удовлетворяет предикату, запустив следующую функцию из 0:
find p := if P p then p else find (S p)
Вы не можете написать эту функцию непосредственно вCoq, но это можно сделать, создав специальное индуктивное предложение.Этот шаблон реализован в модуле выбора библиотеки математических компонентов:
From mathcomp Require Import ssreflect ssrfun ssrbool ssrnat eqtype choice.
(* == is the boolean equality test *)
Definition even n := exists p, (n == 2 * p) = true.
Definition div_2_even_number n (nP : even n) : {p | (n == 2 * p) = true} :=
Sub (xchoose nP) (xchooseP nP).
Функция xchoose : (exists n, P n = true) -> nat
выполняет вышеуказанный поиск, и xchooseP
показывает, что ее результат удовлетворяетлогический предикат.(Фактические типы являются более общими, чем этот, но при создании экземпляра nat
они дают эту сигнатуру.) Я использовал оператор логического равенства, чтобы упростить код, но вместо этого можно было бы использовать =
.
Тем не менее, если вы заботитесь о запуске своего кода, программирование таким способом ужасно неэффективно: вам нужно выполнить n / 2
nat
сравнений, чтобы проверить деление n
.Гораздо лучше написать просто напечатанную версию функции деления:
Fixpoint div2 n :=
match n with
| 0 | 1 => 0
| S (S n) => S (div2 n)
end.