(* given a list of vectors produce the list of all products *)
Fixpoint all_prods (n: nat) (vs: list (vect n)) {struct vs} : list (vect n) :=
match vs with
nil => 1 :: nil
| v::vs1 => let vs1 := all_prods n vs1 in
(map (join n v) vs1 ++ vs1)%list
end.

(* Specifications: *)
(* 1 is the only element of empty product *)
Lemma all_prods_nil n : all_prods n nil = 1 :: nil.
(* If n is the length of the list of vectors, 2^n is the length of the list of all products *)
Lemma all_prods_length n vs :
length (all_prods n vs) = exp 2 (length vs).
(* Lift of all products *)
Lemma all_prods_lift n vs :
all_prods n.+1 (map (lift n) vs) = map (lift n) (all_prods n vs).
Lemma all_prods_hom n vs :
(forall i, In i vs -> exists k, hom n k i) ->
(forall i, In i (all_prods n vs) -> exists k, hom n k i).