After some reading of the completion check in Coq, I think I found a solution:
The completion controller will always disclose local definitions and beta reduction. This is why tree_P1 works.
The completion controller also expands the definitions that are called (for example, list_C' , P , existsb ) existsb , so tree_P2 works.
However, the term verification tester does not expand the definitions that are used in the match … with list_C , for example list_C . The following is a minimal example:
(* works *) Fixpoint foo1 (n : nat) : nat := let t := Some True in match Some True with | Some True => 0 | None => foo1 n end. (* works *) Fixpoint foo2 (n : nat) : nat := let t := Some True in match t with | Some True => 0 | None => foo2 n end. (* does not work *) Definition t := Some True. Fixpoint foo3 (n : nat) : nat := match t with | Some True => 0 | None => foo3 n end.
The source code workaround is to make sure all definitions are invoked (not matched against patterns) to ensure that the completion checker expands them. We can do this by switching to the style of continuing the passage:
Require Import Coq.Lists.List. Record C_dict a := { P' : a -> bool }. Definition C a : Type := forall r, (C_dict a -> r) -> r. Definition P {a} (a_C : C a) : a -> bool := a_C _ (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) := fun _ k => k {| P' := list_P a_C |}. Inductive tree a := Node : a -> list (tree a) -> tree a. (* Works now! *) Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool := let tree_C := fun _ k => k (Build_C_dict _ (tree_P1 a_C)) in match t with Node _ x ts => orb (P a_C x) (P (list_C tree_C) ts) end.
This even works with class types, since class class resolution is an integral of these problems:
Require Import Coq.Lists.List. Record C_dict a := { P' : a -> bool }. Definition C a : Type := forall r, (C_dict a -> r) -> r. Existing Class C. Definition P {a} {a_C : C a} : a -> bool := a_C _ (P' _). Definition list_P {a} `{C a} : list a -> bool := existsb P. Instance list_C {a} (a_C : C a) : C (list a) := fun _ k => k {| P' := list_P |}. Inductive tree a := Node : a -> list (tree a) -> tree a. (* Works now! *) Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool := let tree_C : C (tree a) := fun _ k => k (Build_C_dict _ (tree_P1 a_C)) in match t with Node _ x ts => orb (P x) (P ts) end.
source share