Class Group_op(A : Set) := groupOp : A -> A -> A.Class Group_op(A : Set) := groupOp : A -> A -> A.Infix "^" := groupExp : group_scope.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Class Group
      (GroupElement : Set)
      (groupOp : Group_op GroupElement)
      (ident : GroupElement)
      (inverse : GroupElement -> GroupElement) 
  :={
      
      associativity : 
        forall (x y z : GroupElement),
          (x * y) * z = x * (y * z);
      
      left_identity : 
        forall (a : GroupElement),
          ident * a = a;
      
      right_identity : 
        forall (a : GroupElement),
          a * ident = a;
      
      left_inverse : 
        forall (a : GroupElement),
          (inverse a) * a = ident;
                                                   
      right_inverse : 
        forall (a : GroupElement),
          a * (inverse a) = ident
                                                                                               
    }.Fixpoint groupExp`{G : Group}(a : GroupElement)(n : nat) : GroupElement :=
  match n with
    | 0 => ident
      | S n' => groupOp a (groupExp a n')
  end.

(* Specifications: *)
Lemma groupExp_identity : forall n, ident^n = ident.
Theorem groupExp_plus : forall n1 n2 x, x^(n1 + n2) = (x^n1) * (x^n2).
Theorem groupExp_mult : forall n2 n1 x, ((x^n1)^n2) = (x^(n1 * n2)).