(* We are now ready to define our multiplication *)
Fixpoint join (n : nat) : vect n -> vect n -> vect n :=
  match n return (vect n -> vect n -> vect n) with
  | 0%nat => fun x y => (x * y)%f
  | S n1 =>
      fun x y =>
      let (x1, x2) := x in
      let (y1, y2) := y in (join n1 x1 y2 + join n1 (x2 ^_'f) y1, 
                             join n1 x2 y2)
  end.(* Unicode u2228 *)
Notation "x '∨' y" := (join _ x y) (at level 40, left associativity): type_scope.(* 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: *)
Lemma all_prods_nil n : all_prods n nil = 1 :: nil.
Lemma all_prods_cons n v vs : all_prods n (v :: vs) = (map (join n v) (all_prods n vs) ++ (all_prods n vs))%list.
Lemma all_prods1 n vs : In (1) (all_prods n vs).
Lemma all_prods_id n vs : incl vs (all_prods n vs).
Lemma all_prods_length n vs : length (all_prods n vs) = exp 2 (length 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).