    {-# LANGUAGE CPP #-}
    module Numeric.Product.Commutative
      ( CommutativeProduct (..)
      )
      where

    import Control.Applicative (Const)
    import Data.Complex (Complex)
    import Data.Fixed
    import Data.Functor.Identity
    import Data.Int
    import Data.Ratio (Ratio)
    import Data.Word
    import Numeric.Natural

    #if MIN_VERSION_base(4, 9, 0)
    import Data.Semigroup (Max, Min, Product, Sum)
    #endif

    #if MIN_VERSION_base(4, 11, 0)
    import Data.Ord (Down)
    #endif

    #if MIN_VERSION_base(4, 12, 0)
    import Data.Functor.Contravariant (Op)
    import Data.Monoid (Alt)
    #endif

    -- | Subclass of 'Num' where '(*)' is commutative.
    --
    -- 'Num' doesn't demand commutative '(*)', and there are reasonable
    -- "real-world" instances with non-commutative multiplication. There
    -- is also no canonical subclass in @base@ that would suffice, as both
    -- 'Integral' and 'Floating' imply commutative '(*)' for different
    -- reasons.
    --
    -- Two examples of non-commutative '(*)':
    --
    -- * @Linear.Quaternion.Quaterion@ from the @linear@ package has a
    --   'Num' instance, and quaternion multiplication is
    --   noncommutative.
    --
    -- * @Data.Matrix.Matrix@ from the @matrix@ package uses '(*)' for
    --   matrix multiplication, which is also non-commutative (on square
    --   matrices, which is the only time the question makes sense).
    --
    -- @since 0.1.0
    class Num a => CommutativeProduct a

    instance CommutativeProduct Int8
    instance CommutativeProduct Int16
    instance CommutativeProduct Int32
    instance CommutativeProduct Int64
    instance CommutativeProduct Int
    instance CommutativeProduct Integer

    instance CommutativeProduct Word8
    instance CommutativeProduct Word16
    instance CommutativeProduct Word32
    instance CommutativeProduct Word64
    instance CommutativeProduct Word
    instance CommutativeProduct Natural

    instance CommutativeProduct Float
    instance CommutativeProduct Double

    instance (RealFloat a, CommutativeProduct a) => CommutativeProduct (Complex a)

    instance CommutativeProduct a => CommutativeProduct (Identity a)

    -- @since: base-4.7.0.0
    instance CommutativeProduct a => CommutativeProduct (Sum a)

    -- @since: base-4.7.0.0
    instance (Integral a, CommutativeProduct a) => CommutativeProduct (Ratio a)

    instance (HasResolution a, CommutativeProduct a) => CommutativeProduct (Fixed a)

    #if MIN_VERSION_base(4, 9, 0)
    -- @since: base-4.9.0.0
    instance CommutativeProduct a => CommutativeProduct (Min a)

    -- @since: base-4.9.0.0
    instance CommutativeProduct a => CommutativeProduct (Max a)

    -- @since: base-4.9.0.0
    instance CommutativeProduct a => CommutativeProduct (Product a)

    -- @since: base-4.9.0.0
    instance CommutativeProduct a => CommutativeProduct (Const a b)
    #endif

    #if MIN_VERSION_base(4, 11, 0)
    -- @since: base-4.11.0.0
    instance CommutativeProduct a => CommutativeProduct (Down a)
    #endif

    #if MIN_VERSION_base(4, 12, 0)
    -- @since: base-4.12.0.0
    instance CommutativeProduct a => CommutativeProduct (Op a b)

    -- @since: base-4.12.0.0
    instance CommutativeProduct (f a) => CommutativeProduct (Alt f a)
    #endif