@@ -7,24 +7,36 @@ module Data.HashMap.Strict.NonEmpty
77 singleton ,
88 fromHashMap ,
99 fromList ,
10+ fromNonEmpty ,
1011 toHashMap ,
12+ toList ,
13+ toNonEmpty ,
1114
1215 -- * Basic interface
1316 lookup ,
1417 (!?) ,
1518 keys ,
1619
1720 -- * Combine
21+ union ,
1822 unionWith ,
1923
2024 -- * Transformations
2125 mapKeys ,
26+
27+ -- * Predicates
28+ isInverseOf ,
2229 )
2330where
2431
32+ import Control.DeepSeq (NFData )
33+ import Data.Aeson (FromJSON , ToJSON )
2534import Data.HashMap.Strict (HashMap )
2635import Data.HashMap.Strict qualified as M
36+ import Data.HashMap.Strict.Extended qualified as Extended
2737import Data.Hashable (Hashable )
38+ import Data.List.NonEmpty (NonEmpty )
39+ import Data.List.NonEmpty qualified as NE
2840import Prelude hiding (lookup )
2941
3042-------------------------------------------------------------------------------
@@ -33,7 +45,7 @@ import Prelude hiding (lookup)
3345-- only provides a restricted set of functionalities. It doesn't
3446-- provide a 'Monoid' instance, nor an 'empty' function.
3547newtype NEHashMap k v = NEHashMap { unNEHashMap :: HashMap k v }
36- deriving newtype (Show , Eq , Ord , Semigroup )
48+ deriving newtype (Show , Eq , FromJSON , Hashable , NFData , Ord , Semigroup , ToJSON )
3749 deriving stock (Functor , Foldable , Traversable )
3850
3951-------------------------------------------------------------------------------
@@ -58,10 +70,23 @@ fromList :: (Eq k, Hashable k) => [(k, v)] -> Maybe (NEHashMap k v)
5870fromList [] = Nothing
5971fromList v = Just $ NEHashMap $ M. fromList v
6072
73+ -- | A variant of 'fromList' that uses 'NonEmpty' inputs.
74+ fromNonEmpty :: (Eq k , Hashable k ) => NonEmpty (k , v ) -> NEHashMap k v
75+ fromNonEmpty (x NE. :| xs) = NEHashMap (M. fromList (x : xs))
76+
6177-- | Convert a non-empty map to a 'HashMap'.
6278toHashMap :: NEHashMap k v -> HashMap k v
6379toHashMap = unNEHashMap
6480
81+ -- | Convert a non-empty map to a non-empty list of key/value pairs. The closed
82+ -- operations of 'NEHashMap' guarantee that this operation won't fail.
83+ toNonEmpty :: NEHashMap k v -> NonEmpty (k , v )
84+ toNonEmpty = NE. fromList . M. toList . unNEHashMap
85+
86+ -- | Convert a non-empty map to a list of key/value pairs.
87+ toList :: NEHashMap k v -> [(k , v )]
88+ toList = M. toList . unNEHashMap
89+
6590-------------------------------------------------------------------------------
6691
6792-- | Return the value to which the specified key is mapped, or 'Nothing' if
@@ -84,6 +109,13 @@ keys = M.keys . unNEHashMap
84109
85110-- | The union of two maps.
86111--
112+ -- If a key occurs in both maps, the left map @m1@ (first argument) will be
113+ -- preferred.
114+ union :: (Eq k , Hashable k ) => NEHashMap k v -> NEHashMap k v -> NEHashMap k v
115+ union (NEHashMap m1) (NEHashMap m2) = NEHashMap $ M. union m1 m2
116+
117+ -- | The union of two maps using a given value-wise union function.
118+ --
87119-- If a key occurs in both maps, the provided function (first argument) will be
88120-- used to compute the result.
89121unionWith :: (Eq k , Hashable k ) => (v -> v -> v ) -> NEHashMap k v -> NEHashMap k v -> NEHashMap k v
@@ -98,3 +130,15 @@ unionWith fun (NEHashMap m1) (NEHashMap m2) = NEHashMap $ M.unionWith fun m1 m2
98130-- values is chosen for the conflicting key.
99131mapKeys :: (Eq k2 , Hashable k2 ) => (k1 -> k2 ) -> NEHashMap k1 v -> NEHashMap k2 v
100132mapKeys fun (NEHashMap m) = NEHashMap $ M. mapKeys fun m
133+
134+ -------------------------------------------------------------------------------
135+
136+ -- | Determines whether the left-hand-side and the right-hand-side are inverses of each other.
137+ --
138+ -- More specifically, for two maps @A@ and @B@, 'isInverseOf' is satisfied when both of the
139+ -- following are true:
140+ -- 1. @∀ key ∈ A. A[key] ∈ B ∧ B[A[key]] == key@
141+ -- 2. @∀ key ∈ B. B[key] ∈ A ∧ A[B[key]] == key@
142+ isInverseOf ::
143+ (Eq k , Hashable k , Eq v , Hashable v ) => NEHashMap k v -> NEHashMap v k -> Bool
144+ lhs `isInverseOf` rhs = toHashMap lhs `Extended.isInverseOf` toHashMap rhs
0 commit comments