{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilyDependencies #-}

module Parameterized.Data.Semigroup where

import Data.Kind

type family PNullary (n :: k -> Type) (t :: k) = (r :: Type) | r -> n t

-- | Parameterized version of (<>) in Semigroup
-- If used in conjunction with 'Parameterized.Data.Empty', ie as a parameterized Monoid,
-- then the instance should follow the following laws:
--  * @pmempty' `pmappend'` x = x@
--  * @x `pmappend'` pempty' = x@
--  * @x `pmappend'` (y `pmappend'` z) = (x `pmappend'` y) `pmappend'` z@
class PSemigroup (n :: k -> Type) (t :: k) (u :: k) (v :: k) | t u -> v where
    pmappend :: PNullary n t -> PNullary n u -> PNullary n v

(&<>) :: (PSemigroup n t u v) => PNullary n t -> PNullary n u -> PNullary n v
(&<>) = pmappend
infixr 6 &<>
infixr 6 `pmappend`