Следуя примеру, приведенному в главе GeneralRec книги Chlipala, я пытаюсь написать алгоритм слияния.Написание обоснованных программ в Coq с использованием Fix или Program Fixpoint
Вот мой код
Require Import Nat.
Fixpoint insert (x:nat) (l: list nat) : list nat :=
match l with
| nil => x::nil
| y::l' => if leb x y then
x::l
else
y::(insert x l')
end.
Fixpoint merge (l1 l2 : list nat) : list nat :=
match l1 with
| nil => l2
| x::l1' => insert x (merge l1' l2)
end.
Fixpoint split (l : list nat) : list nat * list nat :=
match l with
| nil => (nil,nil)
| x::nil => (x::nil,nil)
| x::y::l' =>
let (ll,lr) := split l' in
(x::ll,y::lr)
end.
Definition lengthOrder (l1 l2 : list nat) :=
length l1 < length l2.
Theorem lengthOrder_wf : well_founded lengthOrder.
Admitted.
Проблема заключается в том, что это не возможно, чтобы написать функцию сортировки слиянием с командой Fixpoint
, так как функция структурно не уменьшается:
Fixpoint mergeSort (l: list nat) : list nat :=
if leb (length l) 1 then l
else
let (ll,lr) := split l in
merge (mergeSort ll) (mergeSort lr).
Вместо этого один может использовать команду Program Fixpoint
или Definition
с термином Fix
(как в книге Chlipala).
Однако, если я пишу этот
Definition mergeSort : list nat -> list nat.
refine (Fix lengthOrder_wf (fun (l: list nat) => list nat)
(fun (l : list nat) => (fun mergeSort : (forall ls : list nat, lengthOrder ls l -> list nat)=>
if leb (length l) 1 then
let (ll,lr) := split l in
merge (mergeSort ll _) (mergeSort lr _)
else
l))).
я получаю невозможные цели:
2 subgoals, subgoal 1 (ID 65)
l : list nat
mergeSort : forall ls : list nat, lengthOrder ls l -> list nat
ll, lr : list nat
============================
lengthOrder ll l
subgoal 2 (ID 66) is:
lengthOrder lr l
Поэтому Chlipala предлагает изменить определение слиянием таким образом:
Definition mergeSort : list nat -> list nat.
refine (Fix lengthOrder_wf (fun _ => list nat)
(fun (ls : list nat)
(mergeSort : forall ls' : list nat, lengthOrder ls' ls -> list nat) =>
if Compare_dec.le_lt_dec 2 (length ls)
then let lss := split ls in
merge (mergeSort (fst lss) _) (mergeSort (snd lss) _)
else ls)).
, который преследует следующие цели:
2 subgoals, subgoal 1 (ID 68)
ls : list nat
mergeSort : forall ls' : list nat, lengthOrder ls' ls -> list nat
l : 2 <= length ls
lss := split ls : list nat * list nat
============================
lengthOrder (fst lss) ls
subgoal 2 (ID 69) is:
lengthOrder (snd lss) ls
Это новое определение звучит как волшебство для меня. Поэтому я задаюсь вопросом:
- Fom первое определение, можно ли еще доказать доказательство правильности функции?
- Иначе почему первое определение не может работать?
- Как простой пользователь может перейти от первого определения ко второму легко?
'длина (fst (split l)) <длина l' доказуемо! Обратите внимание на то, что в контексте у вас есть H: 2 <= длина l'. Лемма 'split_wf1' в главе CPDT, которую вы связали, очень полезна здесь:' Lemma split_wf1: forall ls, 2 <= length ls -> lengthOrder (fst (split ls)) ls'. –