{-# LANGUAGE Safe #-}

-- | Utilites to work with @Either@ data type.

module Universum.Monad.Either
       ( fromLeft
       , fromRight
       , maybeToLeft
       , maybeToRight
       , leftToMaybe
       , rightToMaybe
       , whenLeft
       , whenLeftM
       , whenRight
       , whenRightM
       ) where

import Control.Applicative (Applicative)
import Control.Monad (Monad (..))
import Data.Function (const)
import Data.Maybe (Maybe (..), maybe)

import Universum.Applicative (pass)
import Universum.Monad.Reexport (Either (..), either)

-- $setup
  > > > import Universum .  (  ( .. ) )

-- | Extracts value from 'Left' or return given default value.
--
  > > > fromLeft 0 ( Left 3 )
  3
  > > > fromLeft 0 ( Right 5 )
  0
fromLeft :: a -> Either a b -> a
fromLeft _ (Left a)  = a
fromLeft a (Right _) = a

-- | Extracts value from 'Right' or return given default value.
--
  > > > fromRight 0 ( Left 3 )
  0
  > > > fromRight 0 ( Right 5 )
  5
fromRight :: b -> Either a b -> b
fromRight b (Left _)  = b
fromRight _ (Right b) = b

-- | Maps left part of 'Either' to 'Maybe'.
--
-- >>> leftToMaybe (Left True)
-- Just True
  > > > leftToMaybe ( Right "  " )
-- Nothing
leftToMaybe :: Either l r -> Maybe l
leftToMaybe = either Just (const Nothing)

-- | Maps right part of 'Either' to 'Maybe'.
--
-- >>> rightToMaybe (Left True)
-- Nothing
  > > > rightToMaybe ( Right "  " )
  Just "  "
rightToMaybe :: Either l r -> Maybe r
rightToMaybe = either (const Nothing) Just

-- | Maps 'Maybe' to 'Either' wrapping default value into 'Left'.
--
  > > >   ( Just "  " )
  Right "  "
-- >>> maybeToRight True Nothing
-- Left True
maybeToRight :: l -> Maybe r -> Either l r
maybeToRight l = maybe (Left l) Right

-- | Maps 'Maybe' to 'Either' wrapping default value into 'Right'.
--
  > > > maybeToLeft True ( Just "  " )
  Left "  "
-- >>> maybeToLeft True Nothing
-- Right True
maybeToLeft :: r -> Maybe l -> Either l r
maybeToLeft r = maybe (Right r) Left

-- | Applies given action to 'Either' content if 'Left' is given.
whenLeft :: Applicative f => Either l r -> (l -> f ()) -> f ()
whenLeft (Left  l) f = f l
whenLeft (Right _) _ = pass
{-# INLINE whenLeft #-}

  | Monadic version of ' whenLeft ' .
whenLeftM :: Monad m => m (Either l r) -> (l -> m ()) -> m ()
whenLeftM me f = me >>= \e -> whenLeft e f
# INLINE whenLeftM #

-- | Applies given action to 'Either' content if 'Right' is given.
whenRight :: Applicative f => Either l r -> (r -> f ()) -> f ()
whenRight (Left  _) _ = pass
whenRight (Right r) f = f r
# INLINE whenRight #

  | Monadic version of ' whenRight ' .
whenRightM :: Monad m => m (Either l r) -> (r -> m ()) -> m ()
whenRightM me f = me >>= \e -> whenRight e f
# INLINE whenRightM #

# LANGUAGE Safe #
 | Utilites to work with @Either@ data type.
 $setup
 | Extracts value from 'Left' or return given default value.

 | Extracts value from 'Right' or return given default value.

 | Maps left part of 'Either' to 'Maybe'.

 >>> leftToMaybe (Left True)
 Just True
 Nothing
 | Maps right part of 'Either' to 'Maybe'.

 >>> rightToMaybe (Left True)
 Nothing
 | Maps 'Maybe' to 'Either' wrapping default value into 'Left'.

 >>> maybeToRight True Nothing
 Left True
 | Maps 'Maybe' to 'Either' wrapping default value into 'Right'.

 >>> maybeToLeft True Nothing
 Right True
 | Applies given action to 'Either' content if 'Left' is given.
# INLINE whenLeft #
 | Applies given action to 'Either' content if 'Right' is given.


module Universum.Monad.Either
       ( fromLeft
       , fromRight
       , maybeToLeft
       , maybeToRight
       , leftToMaybe
       , rightToMaybe
       , whenLeft
       , whenLeftM
       , whenRight
       , whenRightM
       ) where

import Control.Applicative (Applicative)
import Control.Monad (Monad (..))
import Data.Function (const)
import Data.Maybe (Maybe (..), maybe)

import Universum.Applicative (pass)
import Universum.Monad.Reexport (Either (..), either)

  > > > import Universum .  (  ( .. ) )

  > > > fromLeft 0 ( Left 3 )
  3
  > > > fromLeft 0 ( Right 5 )
  0
fromLeft :: a -> Either a b -> a
fromLeft _ (Left a)  = a
fromLeft a (Right _) = a

  > > > fromRight 0 ( Left 3 )
  0
  > > > fromRight 0 ( Right 5 )
  5
fromRight :: b -> Either a b -> b
fromRight b (Left _)  = b
fromRight _ (Right b) = b

  > > > leftToMaybe ( Right "  " )
leftToMaybe :: Either l r -> Maybe l
leftToMaybe = either Just (const Nothing)

  > > > rightToMaybe ( Right "  " )
  Just "  "
rightToMaybe :: Either l r -> Maybe r
rightToMaybe = either (const Nothing) Just

  > > >   ( Just "  " )
  Right "  "
maybeToRight :: l -> Maybe r -> Either l r
maybeToRight l = maybe (Left l) Right

  > > > maybeToLeft True ( Just "  " )
  Left "  "
maybeToLeft :: r -> Maybe l -> Either l r
maybeToLeft r = maybe (Right r) Left

whenLeft :: Applicative f => Either l r -> (l -> f ()) -> f ()
whenLeft (Left  l) f = f l
whenLeft (Right _) _ = pass

  | Monadic version of ' whenLeft ' .
whenLeftM :: Monad m => m (Either l r) -> (l -> m ()) -> m ()
whenLeftM me f = me >>= \e -> whenLeft e f
# INLINE whenLeftM #

whenRight :: Applicative f => Either l r -> (r -> f ()) -> f ()
whenRight (Left  _) _ = pass
whenRight (Right r) f = f r
# INLINE whenRight #

  | Monadic version of ' whenRight ' .
whenRightM :: Monad m => m (Either l r) -> (r -> m ()) -> m ()
whenRightM me f = me >>= \e -> whenRight e f
# INLINE whenRightM #
