module Pandora.Paradigm.Basis.Wye (Wye (..), wye) where

import Pandora.Core.Morphism (($))
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>)))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Applicative (Applicative ((<*>)))
import Pandora.Pattern.Functor.Traversable (Traversable ((->>)))

data Wye a = End | Left a | Right a | Both a a

instance Covariant Wye where
        _ <$> End = End
        f <$> Left x = Left $ f x
        f <$> Right y = Right $ f y
        f <$> Both x y = Both (f x) (f y)

instance Traversable Wye where
        End ->> _ = point End
        Left x ->> f = Left <$> f x
        Right y ->> f = Right <$> f y
        Both x y ->> f = Both <$> f x <*> f y

wye :: r -> (a -> r) -> (a -> r) -> (a -> a -> r) -> Wye a -> r
wye r _ _ _ End = r
wye _ f _ _ (Left x) = f x
wye _ _ g _ (Right y) = g y
wye _ _ _ h (Both x y) = h x y