Я спотыкаюсь о поведении средства проверки завершения Coq, которое я не могу объяснить себе. Рассмотреть возможность:
Require Import Coq.Lists.List.
Record C a := { P : a -> bool }.
Arguments P {_}.
Definition list_P {a} (a_C : C a) : list a -> bool := existsb (P a_C).
Definition list_C {a} (a_C : C a) : C (list a) := {| P := list_P a_C |}.
(* Note that *)
Eval cbn in fun a C => (P (list_C C)).
(* evaluates to: fun a C => list_P C *)
Inductive tree a := Node : a -> list (tree a) -> tree a.
(* Works, using a local record *)
Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P1 a_C) in
let list_C' := Build_C _ (list_P tree_C) in
match t with Node _ x ts => orb (P a_C x) (P list_C' ts) end.
(* Works too, using list_P directly *)
Fixpoint tree_P2 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P2 a_C) in
match t with Node _ x ts => orb (P a_C x) (list_P tree_C ts) end.
(* Does not work, using a globally defined record. Why not? *)
Fixpoint tree_P3 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P3 a_C) in
match t with Node _ x ts => orb (P a_C x) (P (list_C tree_C) ts) end.
Первый и второй примеры показывают, что при попытке понять, завершается ли точка фиксации, Coq может разрешать методы доступа к записи, в основном оценивая то, что мы написали в tree_P1
, по тому, что мы написали в tree_P2
.
Но это, кажется, работает только в том случае, если запись создается локально (let tree_C :=…
), а не в том случае, если она определена с использованием Definition
.
Но Fixpoint
может прекрасно просматривать другие определения, например. через list_P
. Так что же особенного в записях, и могу ли я заставить Coq принимать tree_P3
?