module Data.Neither.Class where

import Prelude hiding (either)
import qualified Data.Either as E
import Data.Neither.Base
import Control.Monad
import Control.Arrow ((&&&))

class Neither e where
  left :: a -> e a b
  right :: b -> e a b
  either :: (a -> c) -> (b -> c) -> e a b -> c

instance Neither Either where
  left = Left
  right = Right
  either = E.either

instance Neither MEither where
  left = MLeft
  right = MRight
  either = meither

instance Neither AEither where
  left = ALeft
  right = ARight
  either = aeither

mapLeft :: Neither e => (a -> c) -> e a b -> e c b
mapLeft = flip mapEither id

mapRight :: Neither e => (b -> c) -> e a b -> e a c
mapRight = mapEither id

mapEither :: Neither e => (a -> c) -> (b -> d) -> e a b -> e c d
mapEither f g = either (left . f) (right . g)

lefts :: (Neither e, MonadPlus m) => m (e a b) -> m a
lefts = (=<<) $ either return (const mzero)

rights :: (Neither e, MonadPlus m) => m (e a b) -> m b
rights = (=<<) $ either (const mzero) return

partitionEithers :: (Neither e, MonadPlus m) => m (e a b) -> (m a, m b)
partitionEithers = lefts &&& rights