The title is not very informative, so let me explain.
I'm trying to formalize what it means to be a term in first-order logic. Here is the textbook definition of terms of an arbitrary language L
:
(1) Each variable or constant is a term.
(2) If n ≥ 1, f is an n-ary function of L, and t1 ... tn are terms of L, then f t1 ... tn is a term of L.
I have already defined variables, constants, functions, and languages as var
, const
, func
, and lang
. I also have functions f_arity
and L_funcs
that returns the arity of a function and the ensemble of all functions in a language, respectively. So giving an inductive definition of terms should be pretty straightforward :
Inductive term ( L : lang ) : Type :=
| t_v : var -> term L
| t_c : const -> term L
| t_f : forall ( f : func )
( l : list ( term L ) ),
length l = f_arity f
-> In func ( L_funcs L ) f
-> term L.
But it doesn't work. Instead, I get this error message.
Error: Non strictly positive occurrence of "term" in
"forall (f : func) (l : list (term L)),
length l = f_arity f -> In func (L_funcs L) f -> term L".
I have a vague idea of what's going on here. The constructor t_f
has an argument length l = f_arity
, which Coq doesn't like because it has term L
on the left side of an arrow. But I think Coq is being overly cautious here, because it lets me do pretty much the same thing if I tweak the types a bit. I could, for instance, define a custom list type listN
indexed by its size,
so that list X n
would be a list of X
with n
elements. Then I would have
Inductive term ( L : lang ) : Type :=
| t_v : var -> term L
| t_c : const -> term L
| t_f : forall ( f : func )
( l : listN ( term L ) ( f_arity f ) ),
In func ( L_funcs L ) f -> term L .
But I don't want to go this way, because it is ad-hoc, and makes all the useful list libraries unusable. So I'm looking for a way to convince Coq that what I'm trying to do is perfectly safe,
so it will accept length l = f_arity f
as a constructor argument. Is there a way to do this?