Що працює
Якщо ввести визначення точки фіксації у списки всередині визначення точки фіксації на деревах, результат буде добре набрано. Це загальний принцип, коли ви вклали рекурсію індуктивного типу, тобто коли рекурсія проходить через такий конструктор list.
Fixpoint size (t : LTree) : nat :=
let size_l := (fix size_l (l : list LTree) : nat :=
match l with
| nil => 0
| h::r => size h + size_l r
end) in
match t with Node l =>
1 + size_l l
end.
Або якщо ви віддаєте перевагу писати це більш коротко:
Fixpoint size (t : LTree) : nat :=
match t with Node l =>
1 + (fix size_l (l : list LTree) : nat :=
match l with
| nil => 0
| h::r => size h + size_l r
end) l
end.
(Я не маю уявлення, з ким я чув це спочатку; це, безумовно, було відкрито незалежно багато разів.)
Загальний рекурсійний предикат
Більш загально, ви можете визначити "правильний" принцип індукції LTreeвручну. Автоматично генерований принцип індукції LTree_rectопускає гіпотезу зі списку, оскільки генератор принципу індукції розуміє лише невкладені строго позитивні випадки індуктивного типу.
LTree_rect =
fun (P : LTree -> Type) (f : forall l : list LTree, P (Node l)) (l : LTree) =>
match l as l0 return (P l0) with
| Node x => f x
end
: forall P : LTree -> Type,
(forall l : list LTree, P (Node l)) -> forall l : LTree, P l
Додамо індукційну гіпотезу до списків. Щоб виконати його в рекурсивному виклику, ми викликаємо принцип індукції списку і передаємо йому принцип індукції дерева на менше дерево всередині списку.
Fixpoint LTree_rect_nest (P : LTree -> Type) (Q : list LTree -> Type)
(f : forall l, Q l -> P (Node l))
(g : Q nil) (h : forall t l, P t -> Q l -> Q (cons t l))
(t : LTree) :=
match t as t0 return (P t0) with
| Node l => f l (list_rect Q g (fun u r => h u r (LTree_rect_nest P Q f g h u)) l)
end.
Чому?
Відповідь на те, чому криється в точних правилах прийому рекурсивних функцій. Ці правила є витонченими, оскільки існує делікатний баланс між дозволенням складних випадків (наприклад, цього, із вкладеною рекурсією у типі даних) та безглуздістю. Coq Довідкове керівництво вводить мову (обчислення індуктивних конструкцій, що є доказом мову Coq), в основному , з формально точними визначеннями, але якщо ви хочете точні правила щодо індукції і коіндукціі вам потрібно піти в науково - дослідних робіт, з цієї теми [1] Едуардо Гіменеса.
FixFixfi{f1:A1:=t1;f2:A2:=t2}
Γ1Γ2=(x:LTree)=(l:listLTree)A1A2=nat=natt1t2=case(x,LTree,λy.g1(f2y))=case(l,listLTree,λhr.g2(f1h)(f2r))
fjtifi
- i=1j=2
ltsize
- i=2j=1
hlsize_l
- i=2j=2
rlsize_l
Причина, чому hвона не є структурно меншою, ніж lза словами перекладача Coq, мені не зрозуміла. Наскільки я розумію з обговорень списку клубів Кок [1] [2], це обмеження в перекладачі, яке в принципі можна було б зняти, але дуже обережно, щоб уникнути неузгодженості.
Список літератури
Кокоріко, Вікі Coq, що не знищує: Взаємна індукція
Список розсилки Coq-Club:
Команда розвитку Coq Помічник доказу Coq: Довідковий посібник . Версія 8.3 (2010). [ веб ] гл. 4 .
Едуардо Гіменес. Кодифікація захищених визначень за допомогою рекурсивних схем . In Types'94: Types для доказів та програм , LNCS 996. Springer-Verlag, 1994. doi: 10.1007 / 3-540-60579-7_3 [ Springer ]
Едуардо Гіменес. Структурно-рекурсивні визначення в теорії типів . В ICALP'98: Матеріали 25-го Міжнародного колоквіуму з питань автоматів, мов та програмування. Springer-Verlag, 1998. [ PDF ]