В «Основах программного обеспечения» есть одно упражнение, которое я уже некоторое время пытаюсь решить правильно, но на самом деле я наткнулся на стену в плане попытки записать запрашиваемую функцию.Вот соответствующая часть упражнения
Рассмотрим другое, более эффективное представление натуральных чисел с использованием двоичной, а не унарной системы.То есть вместо того, чтобы говорить, что каждое натуральное число является либо нулем, либо преемником натурального числа, мы можем сказать, что каждое двоичное число либо
- ноль, либо
- в два раза двоичномчисло или
- двоичное число более чем в два раза.
(a) Сначала напишите индуктивное определение типа bin, соответствующее этому описанию двоичных чисел.
Наивное определение не совсем работает, потому что вы в конечном итоге можете составить термины, которые добавляют 1 к числу, к которому уже добавлен 1, или умножаете ноль на 2 без веской причины.Чтобы избежать тех, что я подумал, я бы закодировал какой-то переход состояния в конструкторы, чтобы избежать их, но это довольно сложно, так что это было лучшее, что я мог придумать
Inductive tag : Type := z | nz | m. (* zero | nonzero | multiply by 2 *)
Inductive bin_nat : tag -> Type :=
(* zero *)
| Zero : bin_nat z
(* nonzero *)
| One : bin_nat nz
(* multiply by 2 -> nonzero *)
| PlusOne : bin_nat m -> bin_nat nz
(* nonzero | multiply by 2 -> multiply by 2 *)
| Multiply : forall {t : tag}, (t = m \/ t = nz) -> bin_nat t -> bin_nat m.
С приведенным выше представлением Iизбегайте вопросов о терминах, которые не имеют смысла, но теперь я должен иметь при себе доказательства всякий раз, когда умножаю на 2. Я на самом деле понятия не имею, как использовать эти вещи в рекурсивных функциях.
Я знаю, какпостроить доказательства и термины, и они выглядят так:
(* nonzero *)
Definition binr (t : tag) := or_intror (t = m) (eq_refl nz).
(* multiply by 2 *)
Definition binl (t : tag) := or_introl (t = nz) (eq_refl tag m).
(* some terms *)
Check Zero.
Check One.
Check (Multiply (binr _) One).
Check (Multiply (binl _) (Multiply (binr _) One)).
Check PlusOne (Multiply (binl _) (Multiply (binr _) One)).
Я также могу записать «доказательство» теоремы, что я хочу соответствовать функции, но я не знаю, как на самом деле преобразоватьэто к функции.Вот доказательство для функции преобразования
Definition binary_to_nat : forall t : tag, bin_nat t -> nat.
Proof.
intros.
einduction H as [ | | b | t proof b ].
{ exact 0. } (* Zero *)
{ exact 1. } (* One *)
{ exact (S (IHb b)). } (* PlusOne *)
{ (* Multiply *)
edestruct t.
cut False.
intros F.
case F.
case proof.
intros F.
inversion F.
intros F.
inversion F.
exact (2 * (IHb b)).
exact (2 * (IHb b)).
}
Defined.
Я знаю, что этот термин - функция, которую я хочу, потому что я могу проверить, что получаю правильные ответы, когда вычисляю с ней
Section Examples.
Example a : binary_to_nat z Zero = 0.
Proof.
lazy.
trivial.
Qed.
Example b : binary_to_nat nz One = 1.
Proof.
lazy.
trivial.
Qed.
Example c : binary_to_nat m ((Multiply (binl _) (Multiply (binr _) One))) = 4.
Proof.
lazy.
trivial.
Qed.
End Examples.
Такнаконец, вопрос: есть ли простой способ преобразовать приведенный выше термин доказательства в реальную функцию простым способом или мне нужно попытаться перепроектировать проверочный термин?