module Pandora.Paradigm.Structure.Graph (Graph, loose) where

import Pandora.Core.Functor (type (:.), type (>))
import Pandora.Core.Morphism ((.), ($))
import Pandora.Paradigm.Basis.Edges (Edges (Empty, Overlay))
import Pandora.Paradigm.Basis.Twister (Twister ((:<)))
import Pandora.Paradigm.Inventory.Stateful (fold)
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>), (<$$>)))
import Pandora.Pattern.Functor.Traversable (Traversable ((->>), (->>>)))
import Pandora.Pattern.Junction.Composition (Composition (Primary, unwrap))

-- | Acyclic graph structure without loops
newtype Graph a = Graph (Edges :. Twister Edges > a)

instance Covariant Graph where
        f <$> Graph stack = Graph $ f <$$> stack

instance Traversable Graph where
        Graph stack ->> f = Graph <$> stack ->>> f

instance Composition Graph where
        type Primary Graph a = Edges :. Twister Edges > a
        unwrap (Graph stack) = stack

-- | Transform any traversable structure into all loose edges graph
loose :: Traversable t => t a -> Graph a
loose = Graph . fold Empty (\x -> Overlay . (:<) x)