I'm stuck while trying to define a recursive function in Coq over a particular type of n-ary tree.
The n-ary tree type I'm using is defined as a mutually inductive type as follows:
Inductive tree : Type :=
| leaf : tree
| node : childs -> tree
with childs : Type :=
| childs_one : tree -> childs
| childs_cons : tree -> childs -> childs.
Note that a node has at least one child. If I want to check that a given Boolean property is verified over all the nodes in a tree, I can write a mutually recursive function to go through the whole structure. However, since the childs
type is close to the list tree
type, and since the standard library offers a lot of lemmas about lists, I want to convert an instance of the childs
type into a list and use the fold_left
function to do the computation. The function I want to write is as follows :
Fixpoint check_nodes (chk : tree -> bool) (t : tree) {struct t} : bool :=
match t with
| leaf => chk t
| node chs => fold_left (fun b ti => b && check_nodes chk ti) (childs2list chs) true
end.
Here, the childs2list
function is a trivial function that converts an instance of the childs
type into of list of tree
. The check_nodes
function does not type-check because the Coq kernel is not able to determine that the ti
parameter of the lambda function passed to fold_left
is a subterm of t
.
I haven't yet managed to find a workaround for this problem. I really want to use the fold_left
function for lists in the definition of my function. My attempts to define the function with the Fix
combinator, and a well-founded relation (based on a "number of nodes" measure) were not successful.
Does anyone have a solution? Or, must I forget about using the fold_left
function?
Here is a complete minimal example:
Require Import Bool.
Require Import List.
Import ListNotations.
Inductive tree : Type :=
| leaf : tree
| node : childs -> tree
with childs : Type :=
| childs_nil : childs
| childs_cons : tree -> childs -> childs.
Fixpoint childs2list (chs : childs) {struct chs} : list tree :=
match chs with
| childs_nil => nil
| childs_cons t chs' => t :: childs2list chs'
end.
Fixpoint check_nodes (chk : tree -> bool) (t : tree) {struct t} : bool :=
match t with
| leaf => chk t
| node chs => fold_left (fun b t__i => b && check_nodes chk t__i) (childs2list chs) true
end.
Many thanks for taking the time to read my question,
Vincent.