{-# LANGUAGE MultiParamTypeClasses,  FunctionalDependencies #-}

module Cats.Cat where

class (Eq o) => Category o a | o -> a, a -> o where
  source :: a -> o
  target :: a -> o
  ident :: o -> a
  unsafeCompose :: a -> a -> a

compose :: (Category o a) => a -> a -> a
compose a0 a1
  | source a1 == target a0 = unsafeCompose a0 a1
  | otherwise = error "Undefined compostion"

data Cat o a = Cat {
    catSource :: a -> o
  , catTarget :: a -> o
  , catIdent :: o -> a
  , catCompose :: a -> a -> a
  }

catObject :: (Category o a) => Cat o a
catObject = Cat {
    catSource = source
  , catTarget = target
  , catIdent = ident
  , catCompose = compose
  }
