{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE PatternSynonyms #-}

{- |

Internal module that re-exports the regular prelude, plus some common useful
functions.

-}

module Prelude
  ( -- * re-exports from useful "default" modules
    module P
    -- * custom operators
  , (...)
    -- * maybe helpers
  , onNothing
  , onNothingM
    -- * either helpers
  , onLeft
  , onLeftM
    -- * sequence helpers
  , Seq (.., Lone)
    -- * hashmap helpers
  , unionWithM
  , unionWithKeyM
  ) where


-- re-exports

import Control.Applicative        as P (liftA, (<|>))
import Control.Arrow              as P (first, left, second, (&&&), (***),
                                        (<<<), (>>>))
import Control.Monad              as P
import Control.Monad.Except       as P
import Control.Monad.Identity     as P
import Control.Monad.Reader       as P
import Control.Monad.State.Strict as P
import Control.Monad.Trans.Maybe  as P (MaybeT (..))
import Data.Bifunctor             as P (bimap)
import Data.Bool                  as P (bool)
import Data.Char                  as P (chr, ord)
import Data.Either                as P (lefts, partitionEithers, rights)
import Data.Foldable              as P (asum, fold, foldMap', foldlM, foldrM,
                                        for_, toList, traverse_)
import Data.Function              as P (on, (&))
import Data.Functor               as P (($>), (<&>))
import Data.Functor.Const         as P (Const (..))
import Data.Hashable              as P (Hashable)
import Data.HashMap.Strict        as P (HashMap, mapKeys)
import Data.HashSet               as P (HashSet)
import Data.List                  as P (find, findIndex, group, intercalate,
                                        intersect, intersperse, lookup, sort,
                                        sortBy, sortOn, union, unionBy, (\\))
import Data.List.NonEmpty         as P (NonEmpty (..), nonEmpty)
import Data.Maybe                 as P (catMaybes, fromMaybe, isJust, isNothing,
                                        listToMaybe, maybeToList)
import Data.Ord                   as P (comparing)
import Data.Semigroup             as P (Semigroup (..))
import Data.Sequence              as P (Seq)
import Data.String                as P (IsString)
import Data.Text                  as P (Text)
import Data.Traversable           as P (for)
import Data.Void                  as P (Void, absurd)
import GHC.Generics               as P (Generic)
import "base" Prelude             as P hiding (lookup)


-- internal imports

import Data.HashMap.Strict        qualified as M
import Data.Sequence              (Seq (..))


-- operators

(...) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
c -> d
f ... :: forall c d a b. (c -> d) -> (a -> b -> c) -> a -> b -> d
... a -> b -> c
g = \a
x b
y -> c -> d
f (a -> b -> c
g a
x b
y)
infixr 8 ...


-- maybe helpers

onNothing :: Applicative m => Maybe a -> m a -> m a
onNothing :: forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing Maybe a
a m a
d = m a -> (a -> m a) -> Maybe a -> m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe m a
d a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
a

onNothingM :: Monad m => m (Maybe a) -> m a -> m a
onNothingM :: forall (m :: * -> *) a. Monad m => m (Maybe a) -> m a -> m a
onNothingM m (Maybe a)
a m a
d = m (Maybe a)
a m (Maybe a) -> (Maybe a -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Maybe a -> m a -> m a) -> m a -> Maybe a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip Maybe a -> m a -> m a
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing m a
d


-- either helpers

onLeft :: Applicative m => Either e a -> (e -> m a) -> m a
onLeft :: forall (m :: * -> *) e a.
Applicative m =>
Either e a -> (e -> m a) -> m a
onLeft Either e a
a e -> m a
f = (e -> m a) -> (a -> m a) -> Either e a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either e -> m a
f a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Either e a
a

onLeftM :: Monad m => m (Either e a) -> (e -> m a) -> m a
onLeftM :: forall (m :: * -> *) e a.
Monad m =>
m (Either e a) -> (e -> m a) -> m a
onLeftM m (Either e a)
a e -> m a
f = m (Either e a)
a m (Either e a) -> (Either e a -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Either e a -> (e -> m a) -> m a)
-> (e -> m a) -> Either e a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip Either e a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
Applicative m =>
Either e a -> (e -> m a) -> m a
onLeft e -> m a
f


-- sequence helpers

pattern Lone :: a -> Seq a
pattern $mLone :: forall {r} {a}. Seq a -> (a -> r) -> ((# #) -> r) -> r
$bLone :: forall a. a -> Seq a
Lone x = x :<| Empty


-- hashmap helpers

unionWithM ::
  (Monad m, Hashable k) =>
  (v -> v -> m v) ->
  HashMap k v ->
  HashMap k v ->
  m (HashMap k v)
unionWithM :: forall (m :: * -> *) k v.
(Monad m, Hashable k) =>
(v -> v -> m v) -> HashMap k v -> HashMap k v -> m (HashMap k v)
unionWithM = (k -> v -> v -> m v)
-> HashMap k v -> HashMap k v -> m (HashMap k v)
forall (m :: * -> *) k v.
(Monad m, Hashable k) =>
(k -> v -> v -> m v)
-> HashMap k v -> HashMap k v -> m (HashMap k v)
unionWithKeyM ((k -> v -> v -> m v)
 -> HashMap k v -> HashMap k v -> m (HashMap k v))
-> ((v -> v -> m v) -> k -> v -> v -> m v)
-> (v -> v -> m v)
-> HashMap k v
-> HashMap k v
-> m (HashMap k v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> v -> m v) -> k -> v -> v -> m v
forall a b. a -> b -> a
const

unionWithKeyM ::
  (Monad m, Hashable k) =>
  (k -> v -> v -> m v) ->
  HashMap k v ->
  HashMap k v ->
  m (HashMap k v)
unionWithKeyM :: forall (m :: * -> *) k v.
(Monad m, Hashable k) =>
(k -> v -> v -> m v)
-> HashMap k v -> HashMap k v -> m (HashMap k v)
unionWithKeyM k -> v -> v -> m v
f HashMap k v
m1 HashMap k v
m2 = (HashMap k v -> (k, v) -> m (HashMap k v))
-> HashMap k v -> [(k, v)] -> m (HashMap k v)
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM HashMap k v -> (k, v) -> m (HashMap k v)
step HashMap k v
m1 (HashMap k v -> [(k, v)]
forall k v. HashMap k v -> [(k, v)]
M.toList HashMap k v
m2)
  where
    step :: HashMap k v -> (k, v) -> m (HashMap k v)
step HashMap k v
m (k
k, v
new) = case k -> HashMap k v -> Maybe v
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
M.lookup k
k HashMap k v
m of
      Maybe v
Nothing -> HashMap k v -> m (HashMap k v)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashMap k v -> m (HashMap k v)) -> HashMap k v -> m (HashMap k v)
forall a b. (a -> b) -> a -> b
$ k -> v -> HashMap k v -> HashMap k v
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
M.insert k
k v
new HashMap k v
m
      Just v
old -> do
        v
combined <- k -> v -> v -> m v
f k
k v
new v
old
        pure $ k -> v -> HashMap k v -> HashMap k v
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
M.insert k
k v
combined HashMap k v
m