module Pandora.Paradigm.Structure.Stack (Stack, push, top, pop, linearize) where
import Pandora.Core.Functor (type (:.:), type (><))
import Pandora.Core.Morphism ((.))
import Pandora.Paradigm.Basis.Twister (Twister ((:<)), unwrap)
import Pandora.Paradigm.Basis.Maybe (Maybe (Just, Nothing))
import Pandora.Paradigm.Inventory.Stateful (fold)
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>)))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Extractable (Extractable (extract))
import Pandora.Pattern.Functor.Alternative (Alternative ((<+>)))
import Pandora.Pattern.Functor.Traversable (Traversable)
import Pandora.Pattern.Functor.Bindable (Bindable ((>>=)))
type Stack a = Maybe :.: Twister Maybe >< a
push :: a -> Stack a -> Stack a
push x stack = ((:<) x . Just <$> stack) <+> (point . point) x
top :: Stack a -> Maybe a
top stack = extract <$> stack
pop :: Stack a -> Stack a
pop stack = stack >>= unwrap
linearize :: Traversable t => t a -> Stack a
linearize = fold Nothing (\x -> Just . (:<) x)