{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Data.Mergeable.IsMap
  ( IsMap (..),
    selectBy,
    selectOr,
    FromList (..),
  )
where

import Control.Monad.Except (MonadError (throwError))
import qualified Data.HashMap.Lazy as HM
import Data.Mergeable.Internal.Merge (mergeNoDuplicates)
import Data.Mergeable.Internal.NameCollision (NameCollision)
import Relude

class IsMap k m | m -> k where
  unsafeFromList :: [(k, a)] -> m a

  singleton :: k -> a -> m a

  lookup :: k -> m a -> Maybe a

  member :: k -> m a -> Bool
  member = Bool -> (a -> Bool) -> k -> m a -> Bool
forall k (c :: * -> *) d a.
IsMap k c =>
d -> (a -> d) -> k -> c a -> d
selectOr Bool
False (Bool -> a -> Bool
forall a b. a -> b -> a
const Bool
True)

instance (Eq k, Hashable k) => IsMap k (HashMap k) where
  unsafeFromList :: [(k, a)] -> HashMap k a
unsafeFromList = [(k, a)] -> HashMap k a
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList
  singleton :: k -> a -> HashMap k a
singleton = k -> a -> HashMap k a
forall k v. Hashable k => k -> v -> HashMap k v
HM.singleton
  lookup :: k -> HashMap k a -> Maybe a
lookup = k -> HashMap k a -> Maybe a
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup
  member :: k -> HashMap k a -> Bool
member = k -> HashMap k a -> Bool
forall k a. (Eq k, Hashable k) => k -> HashMap k a -> Bool
HM.member

selectBy :: (MonadError e m, IsMap k c, Monad m) => e -> k -> c a -> m a
selectBy :: e -> k -> c a -> m a
selectBy e
err = m a -> (a -> m a) -> k -> c a -> m a
forall k (c :: * -> *) d a.
IsMap k c =>
d -> (a -> d) -> k -> c a -> d
selectOr (e -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError e
err) a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

selectOr :: IsMap k c => d -> (a -> d) -> k -> c a -> d
selectOr :: d -> (a -> d) -> k -> c a -> d
selectOr d
fb a -> d
f k
key c a
lib = d -> (a -> d) -> Maybe a -> d
forall b a. b -> (a -> b) -> Maybe a -> b
maybe d
fb a -> d
f (k -> c a -> Maybe a
forall k (m :: * -> *) a. IsMap k m => k -> m a -> Maybe a
lookup k
key c a
lib)

class FromList m map k a where
  fromList :: (Monad m) => [(k, a)] -> m (map k a)

instance (Hashable k, Eq k, MonadError e m, NameCollision e a) => FromList m HashMap k a where
  fromList :: [(k, a)] -> m (HashMap k a)
fromList = ([(k, a)] -> HashMap k a) -> [(k, a)] -> m (HashMap k a)
forall k (m :: * -> *) e a b.
(Eq k, Hashable k, Monad m, MonadError e m, NameCollision e a) =>
([(k, a)] -> b) -> [(k, a)] -> m b
mergeNoDuplicates [(k, a)] -> HashMap k a
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList