monoidmap-0.0.1.2: src/examples/Examples/NestedMonoidMap.hs
{-# LANGUAGE TypeSynonymInstances #-}
-- |
-- Copyright: © 2022–2024 Jonathan Knowles
-- License: Apache-2.0
--
-- A nested map with compound keys, implemented in terms of 'MonoidMap'.
--
module Examples.NestedMonoidMap
(
-- * Type
NestedMonoidMap
-- * Construction
, fromFlatList
, fromFlatMap
, fromNestedList
, fromNestedMap
-- * Deconstruction
, toFlatList
, toFlatMap
, toNestedList
, toNestedMap
-- * Basic operations
, get
, set
, adjust
, nullify
-- * Membership
, nonNullCount
, nonNullKey
, nonNullKeys
-- * Intersection
, intersection
, intersectionWith
-- * Union
, union
, unionWith
-- * Comparison
, isSubmapOf
, isSubmapOfBy
, disjoint
, disjointBy
)
where
import Prelude
import Data.Map.Strict
( Map )
import Data.Monoid
( Sum (..) )
import Data.Monoid.GCD
( GCDMonoid, LeftGCDMonoid, OverlappingGCDMonoid, RightGCDMonoid )
import Data.Monoid.LCM
( LCMMonoid )
import Data.Monoid.Monus
( Monus )
import Data.Monoid.Null
( MonoidNull, PositiveMonoid )
import Data.MonoidMap
( MonoidMap )
import Data.Semigroup.Cancellative
( Cancellative
, Commutative
, LeftCancellative
, LeftReductive
, Reductive
, RightCancellative
, RightReductive
)
import Data.Set
( Set )
import GHC.Exts
( IsList (..) )
import qualified Data.Foldable as F
import qualified Data.Map.Strict as Map
import qualified Data.MonoidMap as MonoidMap
import qualified Data.Set as Set
--------------------------------------------------------------------------------
-- Type
--------------------------------------------------------------------------------
newtype NestedMonoidMap k1 k2 v =
NestedMonoidMap (MonoidMap k1 (MonoidMap k2 v))
deriving stock Eq
deriving newtype
( Cancellative
, Commutative
, GCDMonoid
, LCMMonoid
, LeftCancellative
, LeftGCDMonoid
, LeftReductive
, Monoid
, MonoidNull
, Monus
, OverlappingGCDMonoid
, PositiveMonoid
, Reductive
, RightCancellative
, RightGCDMonoid
, RightReductive
, Semigroup
, Show
)
--------------------------------------------------------------------------------
-- Construction
--------------------------------------------------------------------------------
fromFlatList
:: (Ord k1, Ord k2, MonoidNull v)
=> [((k1, k2), v)]
-> NestedMonoidMap k1 k2 v
fromFlatList = F.foldl' acc mempty
where
acc m ((k1, k2), v) = adjust (<> v) k1 k2 m
fromFlatMap
:: (Ord k1, Ord k2, MonoidNull v)
=> Map (k1, k2) v
-> NestedMonoidMap k1 k2 v
fromFlatMap = fromFlatList . Map.toList
fromNestedList
:: (Ord k1, Ord k2, MonoidNull v)
=> [(k1, [(k2, v)])]
-> NestedMonoidMap k1 k2 v
fromNestedList entries =
fromFlatList [((k1, k2), v) | (k1, n) <- entries, (k2, v) <- n]
fromNestedMap
:: (Ord k2, MonoidNull v)
=> Map k1 (Map k2 v)
-> NestedMonoidMap k1 k2 v
fromNestedMap = NestedMonoidMap . MonoidMap.fromMap . fmap MonoidMap.fromMap
--------------------------------------------------------------------------------
-- Deconstruction
--------------------------------------------------------------------------------
toFlatList
:: (Ord k1, Ord k2, MonoidNull v)
=> NestedMonoidMap k1 k2 v
-> [((k1, k2), v)]
toFlatList m = [((k1, k2), v) | (k1, n) <- toNestedList m, (k2, v) <- toList n]
toFlatMap
:: (Ord k1, Ord k2, MonoidNull v)
=> NestedMonoidMap k1 k2 v
-> Map (k1, k2) v
toFlatMap = Map.fromList . toFlatList
toNestedList
:: (Ord k1, Ord k2, MonoidNull v)
=> NestedMonoidMap k1 k2 v
-> [(k1, [(k2, v)])]
toNestedList (NestedMonoidMap m) = fmap toList <$> toList m
toNestedMap
:: NestedMonoidMap k1 k2 v
-> Map k1 (Map k2 v)
toNestedMap (NestedMonoidMap m) = MonoidMap.toMap <$> MonoidMap.toMap m
--------------------------------------------------------------------------------
-- Basic operations
--------------------------------------------------------------------------------
get :: (Ord k1, Ord k2, MonoidNull v)
=> k1
-> k2
-> NestedMonoidMap k1 k2 v
-> v
get k1 k2 (NestedMonoidMap m) = MonoidMap.get k2 (MonoidMap.get k1 m)
set :: (Ord k1, Ord k2, MonoidNull v)
=> k1
-> k2
-> v
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
set k1 k2 v (NestedMonoidMap m) =
NestedMonoidMap $ MonoidMap.adjust (MonoidMap.set k2 v) k1 m
adjust
:: (Ord k1, Ord k2, MonoidNull v)
=> (v -> v)
-> k1
-> k2
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
adjust f k1 k2 (NestedMonoidMap m) =
NestedMonoidMap $ MonoidMap.adjust (MonoidMap.adjust f k2) k1 m
nullify
:: (Ord k1, Ord k2, MonoidNull v)
=> k1
-> k2
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
nullify k1 k2 (NestedMonoidMap m) =
NestedMonoidMap $ MonoidMap.adjust (MonoidMap.nullify k2) k1 m
--------------------------------------------------------------------------------
-- Membership
--------------------------------------------------------------------------------
nonNullCount :: NestedMonoidMap k1 k2 v -> Int
nonNullCount (NestedMonoidMap m) =
getSum $ F.foldMap (Sum . MonoidMap.nonNullCount) m
nonNullKey
:: (Ord k1, Ord k2, MonoidNull v)
=> k1
-> k2
-> NestedMonoidMap k1 k2 v
-> Bool
nonNullKey k1 k2 (NestedMonoidMap m) =
MonoidMap.nonNullKey k2 (MonoidMap.get k1 m)
nonNullKeys
:: (Ord k1, Ord k2, MonoidNull v)
=> NestedMonoidMap k1 k2 v
-> Set (k1, k2)
nonNullKeys = Set.fromList . fmap fst . toFlatList
--------------------------------------------------------------------------------
-- Intersection
--------------------------------------------------------------------------------
intersection
:: (Ord k1, Ord k2, MonoidNull v, GCDMonoid v)
=> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
intersection (NestedMonoidMap m1) (NestedMonoidMap m2) = NestedMonoidMap $
MonoidMap.intersection m1 m2
intersectionWith
:: (Ord k1, Ord k2, MonoidNull v)
=> (v -> v -> v)
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
intersectionWith f (NestedMonoidMap m1) (NestedMonoidMap m2) = NestedMonoidMap $
MonoidMap.intersectionWith (MonoidMap.intersectionWith f) m1 m2
--------------------------------------------------------------------------------
-- Union
--------------------------------------------------------------------------------
union
:: (Ord k1, Ord k2, MonoidNull v, LCMMonoid v)
=> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
union (NestedMonoidMap m1) (NestedMonoidMap m2) = NestedMonoidMap $
MonoidMap.union m1 m2
unionWith
:: (Ord k1, Ord k2, MonoidNull v)
=> (v -> v -> v)
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
unionWith f (NestedMonoidMap m1) (NestedMonoidMap m2) = NestedMonoidMap $
MonoidMap.unionWith (MonoidMap.unionWith f) m1 m2
--------------------------------------------------------------------------------
-- Comparison
--------------------------------------------------------------------------------
isSubmapOf
:: (Ord k1, Ord k2, MonoidNull v, Reductive v)
=> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> Bool
isSubmapOf (NestedMonoidMap m1) (NestedMonoidMap m2) =
MonoidMap.isSubmapOf m1 m2
isSubmapOfBy
:: (Ord k1, Ord k2, MonoidNull v, Reductive v)
=> (v -> v -> Bool)
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> Bool
isSubmapOfBy f (NestedMonoidMap m1) (NestedMonoidMap m2) =
MonoidMap.isSubmapOfBy (MonoidMap.isSubmapOfBy f) m1 m2
disjoint
:: (Ord k1, Ord k2, MonoidNull v, GCDMonoid v)
=> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> Bool
disjoint (NestedMonoidMap m1) (NestedMonoidMap m2) =
MonoidMap.disjoint m1 m2
disjointBy
:: (Ord k1, Ord k2, MonoidNull v, GCDMonoid v)
=> (v -> v -> Bool)
-> NestedMonoidMap k1 k2 v
-> NestedMonoidMap k1 k2 v
-> Bool
disjointBy f (NestedMonoidMap m1) (NestedMonoidMap m2) =
MonoidMap.disjointBy (MonoidMap.disjointBy f) m1 m2