module Lighthouse.Utils.General
    ( fst3, snd3, thd3
    , liftMaybe, maybeToRight, rightToMaybe
    , (<.$>), (<$.>), (<.$.>)
    , whileM_
    ) where

import Control.Monad (when)
import Control.Monad.Trans.Maybe

-- | Lifts an optional value into the maybe transformer.
liftMaybe :: Monad m => Maybe a -> MaybeT m a
liftMaybe :: forall (m :: * -> *) a. Monad m => Maybe a -> MaybeT m a
liftMaybe = m (Maybe a) -> MaybeT m a
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (m (Maybe a) -> MaybeT m a)
-> (Maybe a -> m (Maybe a)) -> Maybe a -> MaybeT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe a -> m (Maybe a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return

-- | The right element or the given value.
maybeToRight :: b -> Maybe a -> Either b a
maybeToRight :: forall b a. b -> Maybe a -> Either b a
maybeToRight b
x Maybe a
Nothing  = b -> Either b a
forall a b. a -> Either a b
Left b
x
maybeToRight b
_ (Just a
y) = a -> Either b a
forall a b. b -> Either a b
Right a
y

-- | The right side of the either.
rightToMaybe :: Either a b -> Maybe b
rightToMaybe :: forall a b. Either a b -> Maybe b
rightToMaybe (Left a
_)  = Maybe b
forall a. Maybe a
Nothing
rightToMaybe (Right b
y) = b -> Maybe b
forall a. a -> Maybe a
Just b
y

-- | Fetches the first element of a triple.
fst3 :: (a, b, c) -> a
fst3 :: forall a b c. (a, b, c) -> a
fst3 (a
x, b
_, c
_) = a
x

-- | Fetches the second element of a triple.
snd3 :: (a, b, c) -> b
snd3 :: forall a b c. (a, b, c) -> b
snd3 (a
_, b
y, c
_) = b
y

-- | Fetches the third element of a triple.
thd3 :: (a, b, c) -> c
thd3 :: forall a b c. (a, b, c) -> c
thd3 (a
_, b
_, c
z) = c
z

-- | Maps over the first element in a pair.
(<.$>) :: (a -> b) -> (a, c) -> (b, c)
a -> b
f <.$> :: forall a b c. (a -> b) -> (a, c) -> (b, c)
<.$> (a
x, c
y) = (a -> b
f a
x, c
y)

-- | Maps over the second element in a pair.
(<$.>) :: (a -> b) -> (c, a) -> (c, b)
a -> b
f <$.> :: forall a b c. (a -> b) -> (c, a) -> (c, b)
<$.> (c
x, a
y) = (c
x, a -> b
f a
y)

-- | Maps over both elements of a pair.
(<.$.>) :: (a -> b) -> (a, a) -> (b, b)
<.$.> :: forall a b. (a -> b) -> (a, a) -> (b, b)
(<.$.>) a -> b
f = (a -> b
f (a -> b) -> (b, a) -> (b, b)
forall a b c. (a -> b) -> (c, a) -> (c, b)
<$.>) ((b, a) -> (b, b)) -> ((a, a) -> (b, a)) -> (a, a) -> (b, b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b
f (a -> b) -> (a, a) -> (b, a)
forall a b c. (a -> b) -> (a, c) -> (b, c)
<.$>)

-- | Loops while the given condition is true.
whileM_ :: Monad m => m Bool -> m a -> m ()
whileM_ :: forall (m :: * -> *) a. Monad m => m Bool -> m a -> m ()
whileM_ m Bool
cond m a
body = do
    Bool
c <- m Bool
cond
    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
c (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
        a
_ <- m a
body
        m Bool -> m a -> m ()
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m ()
whileM_ m Bool
cond m a
body