{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.List.EitherFunctions
  ( partlyMap
  , groupEither
  , spanLeft
  , spanRight
  ) where

import Data.Either (Either (..))
import Data.List   (map)
import Data.Maybe  (Maybe (..), maybe)

{- |

>>> import Prelude (even, show)

>>> partlyMap (\x -> if even x then Just (show x) else Nothing) [1..5]
[Left 1,Right "2",Left 3,Right "4",Left 5]

-}
partlyMap :: (a -> Maybe b) -> [a] -> [Either a b]
partlyMap f = map (\x -> maybe (Left x) Right (f x))

{- |

>>> groupEither [Left 1, Left 2, Right 'a', Left 3, Right 'b', Right 'c']
[Left [1,2],Right "a",Left [3],Right "bc"]

-}
groupEither :: [Either a b] -> [Either [a] [b]]
groupEither [] = []
groupEither ((Left x) : xs)  = let (ys, zs) = spanLeft xs
                               in  Left (x : ys) : groupEither zs
groupEither ((Right x) : xs) = let (ys, zs) = spanRight xs
                               in  Right (x : ys) : groupEither zs

{- |

>>> spanLeft [Left 1, Left 2, Right 'a', Left 3, Right 'b', Right 'c']
([1,2],[Right 'a',Left 3,Right 'b',Right 'c'])

>>> spanLeft [Right 'a', Left 3, Right 'b', Right 'c']
([],[Right 'a',Left 3,Right 'b',Right 'c'])

-}
spanLeft :: [Either a b] -> ([a], [Either a b])
spanLeft [] = ([], [])
spanLeft ((Left x) : xs) = let (ys, zs) = spanLeft xs
                           in  (x : ys, zs)
spanLeft xs = ([], xs)

{- |

>>> spanRight [Left 1, Left 2, Right 'a', Left 3, Right 'b', Right 'c']
("",[Left 1,Left 2,Right 'a',Left 3,Right 'b',Right 'c'])

>>> spanRight [Right 'a', Left 3, Right 'b', Right 'c']
("a",[Left 3,Right 'b',Right 'c'])

-}
spanRight :: [Either a b] -> ([b], [Either a b])
spanRight [] = ([], [])
spanRight ((Right x) : xs) = let (ys, zs) = spanRight xs
                             in  (x : ys, zs)
spanRight xs = ([], xs)