module Product where import qualified Prelude as P import Data.Constraint hiding ((***), (&&&)) import Data.Proxy import Data.Tagged import Category import Category.Product import Functor import Terminal import TerminalMorphism import Monoidal class Category c => ProductCategory (c :: k -> k -> *) where type (><) (a :: k) (b :: k) :: k productObjectMap :: Tagged '(c, a, b) ((Object c a, Object c b) :- Object c (a >< b)) univProduct :: forall (a :: k) (b :: k). Tagged '(c, a, b) ((Object c a, Object c b) :- TerminalMorphism (Diag c) (a >< b) '(a, b)) proj1 :: forall a b c. (ProductCategory c, Object c a, Object c b) => Tagged b (c (a >< b) a) proj1 = Tagged p where p :><: _ = t t :: (c :><: c) '(a >< b, a >< b) '(a, b) t = proxy terminalMorphism (Proxy :: Proxy '(Diag c, a >< b)) \\ proxy univProduct (Proxy :: Proxy '(c, a, b)) proj2 :: forall a b c. (ProductCategory c, Object c a, Object c b) => Tagged a (c (a >< b) b) proj2 = Tagged p where _ :><: p = t t :: (c :><: c) '(a >< b, a >< b) '(a, b) t = proxy terminalMorphism (Proxy :: Proxy '(Diag c, a >< b)) \\ proxy univProduct (Proxy :: Proxy '(c, a, b)) (&&&) :: forall c a b1 b2. ProductCategory c => c a b1 -> c a b2 -> c a (b1 >< b2) f &&& g | Dict <- observeObjects f, Dict <- observeObjects g = proxy terminalFactorization (Proxy :: Proxy (Diag c)) (f :><: g) \\ proxy univProduct (Proxy :: Proxy '(c, b1, b2)) (***) :: forall c a1 a2 b1 b2. ProductCategory c => c a1 b1 -> c a2 b2 -> c (a1 >< a2) (b1 >< b2) f *** g = proxy morphMap (Proxy :: Proxy (ProductF c)) (f :><: g) data ProductF c where ProductF :: ProductCategory c => ProductF c instance ProductCategory (c :: k -> k -> *) => Functor (ProductF c) ('KProxy :: KProxy ((k, k) -> k)) where type Domain (ProductF c) = c :><: c type Codomain (ProductF c) = c type FMap (ProductF c) (a :: (k, k)) = L a >< R a morphMap :: forall (a :: (k, k)) (b :: (k, k)). Tagged (ProductF c) (Domain (ProductF c) a b -> Codomain (ProductF c) (FMap (ProductF c) a :: k) (FMap (ProductF c) b :: k)) morphMap = Tagged m where m (f :><: g) | Dict <- observeObjects f, Dict <- observeObjects g = (f . (proxy proj1 (Proxy :: Proxy (R a)))) &&& (g . (proxy proj2 (Proxy :: Proxy (L a)))) instance (ProductCategory c, Terminal c) => Monoidal c where type Mu c = ProductF c type I c = T c instance TerminalMorphism (Diag (->)) (a, b) '(a, b) where terminalMorphism = Tagged (P.fst :><: P.snd) terminalFactorization = Tagged (\(f :><: g) z -> (f z, g z)) instance ProductCategory (->) where type (><) a b = (a, b) productObjectMap = Tagged (Sub Dict) univProduct = Tagged (Sub Dict) instance TerminalMorphism (Diag (:-)) ((a :: Constraint), b) '(a, b) where terminalMorphism = Tagged (Sub Dict :><: Sub Dict) terminalFactorization = Tagged (\(f :><: g) -> Sub (Dict \\ f \\ g)) instance ProductCategory (:-) where type (><) a b = ((a, b) :: Constraint) productObjectMap = Tagged (Sub Dict) univProduct = Tagged (Sub Dict)