Do you know about Lawvere theories? The unifying approach to laws there is to have a signature associated with a class of algebraic objects. In Haskell, we could hide the arity of the signature in a type family. Roughly speaking,
class Lawvere (theory :: Type -> Constraint) where
type Signature theory :: Type -> Type
operations :: theory a => Signature theory a -> a
type Laws theory :: Type -> Type
lawful :: (theory a, Eq a) => Laws theory a -> Bool
data MonoidLaws a where
NeutralLeft :: a -> MonoidLaws a
NeutralRight :: a -> MonoidLaws a
Assoc :: a -> a -> a -> MonoidLaws a
lawfulMonoid :: (Monoid a, Eq a) => MonoidLaws a -> Bool
lawfulMonoid (NeutralLeft a) = a == mempty `mappend` a
lawfulMonoid (NeutralRight a) = a == a `mappend` mempty
lawfulMonoid (Assoc x y z) = mappend (mappend x y) z == mappend x (mappend y z)
instance Lawvere Monoid where
type Signature Monoid a = Either () (a,a)
operations (Left ()) = mempty
operations (Right (x,y)) = mappend x y
type Laws Monoid a = MonoidLaws a
lawful = lawfulMonoid
Lawvere combined the signature and laws in a single category L (objects = arities, morphisms = laws) and instances of the theory (models) are then functors from this category. Homomorphisms are natural transformations between such functors.
For the sake of efficiency, one could formulate the laws as Haskell rewrite rules.
EDIT: For a more principled approach, see this topic.