    {-# LANGUAGE DeriveFunctor #-}
    {-# LANGUAGE DeriveFoldable #-}
    {-# LANGUAGE DeriveTraversable #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Data.Aeson.Config.Types where

    import           Data.Semigroup (Semigroup(..))
    import           Data.Bitraversable
    import           Data.Bifoldable
    import           Data.Bifunctor

    import           Data.Aeson.Config.FromValue

    newtype List a = List {fromList :: [a]}
      deriving (Eq, Show, Functor, Foldable, Traversable, Semigroup, Monoid)

    instance FromValue a => FromValue (List a) where
      fromValue v = List <$> case v of
        Array _ -> fromValue v
        _ -> return <$> fromValue v

    fromMaybeList :: Maybe (List a) -> [a]
    fromMaybeList = maybe [] fromList

    data Product a b = Product a b
      deriving (Eq, Show, Functor, Foldable, Traversable)

    instance (Semigroup a, Semigroup b, Monoid a, Monoid b) => Monoid (Product a b) where
      mempty = Product mempty mempty
      mappend = (<>)

    instance (Semigroup a, Semigroup b) => Semigroup (Product a b) where
      Product a1 b1 <> Product a2 b2 = Product (a1 <> a2) (b1 <> b2)

    instance Bifunctor Product where
      bimap fa fb (Product a b) = Product (fa a) (fb b)

    instance Bifoldable Product where
      bifoldMap = bifoldMapDefault

    instance Bitraversable Product where
      bitraverse fa fb (Product a b) = Product <$> fa a <*> fb b

    instance (FromValue a, FromValue b) => FromValue (Product a b) where
      fromValue v = Product <$> fromValue v <*> fromValue v