From 22d6fe3bcfb7f056b8a5ac8b26ee67e11fc9b032 Mon Sep 17 00:00:00 2001 From: Mikolaj Konarski Date: Tue, 23 Dec 2025 18:38:38 +0100 Subject: Make the code more strict for a tiny performance gain --- src/Data/Dependent/EnumMap/Strict/Internal.hs | 42 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Data/Dependent/EnumMap/Strict/Internal.hs b/src/Data/Dependent/EnumMap/Strict/Internal.hs index be18ae9..05e130e 100644 --- a/src/Data/Dependent/EnumMap/Strict/Internal.hs +++ b/src/Data/Dependent/EnumMap/Strict/Internal.hs @@ -14,6 +14,7 @@ module Data.Dependent.EnumMap.Strict.Internal where import Prelude hiding (lookup, map) import Control.Exception +import Control.Monad ((<$!>)) import Data.Bifunctor (bimap, second) import Data.Coerce import Data.Dependent.Sum @@ -192,7 +193,7 @@ insertLookupWithKey f k v (DEnumMap m) = -- Second note: the BangPatterns don't do anything operationally because -- with the current implementation of IM.insertLookupWithKey, the pair -- components are already strict. - in ((\(KV _ v2) -> coe1 v2) <$> mx, DEnumMap m') + in ((\(KV _ v2) -> coe1 v2) <$!> mx, DEnumMap m') -- * Deletion\/Update @@ -228,7 +229,7 @@ updateLookupWithKey f k (DEnumMap m) = Refl -> KV inf <$> f k v) i m -- Note: type checking unnecessary here for the same reason as insertLookupWithKey - in ((\(KV _ v2) -> coe1 v2) <$> mx, DEnumMap m') + in ((\(KV _ v2) -> coe1 v2) <$!> mx, DEnumMap m') alter :: forall k v a. (Enum1 k, TestEquality k) => (Maybe (v a) -> Maybe (v a)) -> k a -> DEnumMap k v -> DEnumMap k v @@ -259,7 +260,8 @@ lookup :: (Enum1 k, TestEquality k) => k a -> DEnumMap k v -> Maybe (v a) lookup k (DEnumMap m) = let (i, _) = fromEnum1 k in (\(KV inf v) -> case typeCheck1 k i inf of - Refl -> v) <$> IM.lookup i m + Refl -> v) + <$!> IM.lookup i m (!?) :: (Enum1 k, TestEquality k) => DEnumMap k v -> k a -> Maybe (v a) (!?) m k = lookup k m @@ -284,10 +286,10 @@ notMember :: Enum1 k => k a -> DEnumMap k v -> Bool notMember k m = not $ member k m lookupLT, lookupGT, lookupLE, lookupGE :: Enum1 k => k a -> DEnumMap k v -> Maybe (DSum k v) -lookupLT k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$> IM.lookupLT i m -lookupGT k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$> IM.lookupGT i m -lookupLE k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$> IM.lookupLE i m -lookupGE k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$> IM.lookupGE i m +lookupLT k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$!> IM.lookupLT i m +lookupGT k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$!> IM.lookupGT i m +lookupLE k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$!> IM.lookupLE i m +lookupGE k (DEnumMap m) = let (i, _) = fromEnum1 k in kVToDSum <$!> IM.lookupGE i m -- ** Size @@ -592,9 +594,9 @@ split k (DEnumMap m) = bimap DEnumMap DEnumMap (IM.split (fst $ fromEnum1 k) m) splitLookup :: Enum1 k => k a -> DEnumMap k v -> (DEnumMap k v, Maybe (v a), DEnumMap k v) splitLookup k (DEnumMap m) = - let (m1, mkv, m2) = IM.splitLookup (fst $ fromEnum1 k) m + let (!m1, !mkv, !m2) = IM.splitLookup (fst $ fromEnum1 k) m -- Note: this coe1 is fine because of the invariant on DEnumMap. - in (DEnumMap m1, (\(KV _ v) -> coe1 v) <$> mkv, DEnumMap m2) + in (DEnumMap m1, (\(KV _ v) -> coe1 v) <$!> mkv, DEnumMap m2) splitRoot :: DEnumMap k v -> [DEnumMap k v] splitRoot (DEnumMap m) = DEnumMap <$> IM.splitRoot m @@ -619,10 +621,10 @@ isProperSubmapOfBy f (DEnumMap m1) (DEnumMap m2) = -- * Min\/Max lookupMin :: Enum1 k => DEnumMap k v -> Maybe (DSum k v) -lookupMin (DEnumMap m) = kVToDSum <$> IM.lookupMin m +lookupMin (DEnumMap m) = kVToDSum <$!> IM.lookupMin m lookupMax :: Enum1 k => DEnumMap k v -> Maybe (DSum k v) -lookupMax (DEnumMap m) = kVToDSum <$> IM.lookupMax m +lookupMax (DEnumMap m) = kVToDSum <$!> IM.lookupMax m findMin :: Enum1 k => DEnumMap k v -> DSum k v findMin (DEnumMap m) = kVToDSum $ IM.findMin m @@ -637,10 +639,10 @@ deleteMax :: DEnumMap k v -> DEnumMap k v deleteMax (DEnumMap m) = DEnumMap $ IM.deleteMax m deleteFindMin :: Enum1 k => DEnumMap k v -> (DSum k v, DEnumMap k v) -deleteFindMin (DEnumMap m) = bimap kVToDSum DEnumMap $ IM.deleteFindMin m +deleteFindMin (DEnumMap m) = bimap' kVToDSum DEnumMap $ IM.deleteFindMin m deleteFindMax :: Enum1 k => DEnumMap k v -> (DSum k v, DEnumMap k v) -deleteFindMax (DEnumMap m) = bimap kVToDSum DEnumMap $ IM.deleteFindMax m +deleteFindMax (DEnumMap m) = bimap' kVToDSum DEnumMap $ IM.deleteFindMax m updateMin :: Enum1 k => (forall a. v a -> Maybe (v a)) -> DEnumMap k v -> DEnumMap k v updateMin f = updateMinWithKey (const f) @@ -657,16 +659,16 @@ updateMaxWithKey f (DEnumMap m) = DEnumMap (IM.updateMaxWithKey (\i (KV inf v) -> case toEnum1 i inf of k -> KV inf <$> f k v) m) minView :: DEnumMap k v -> Maybe (v a, DEnumMap k v) -minView (DEnumMap m) = bimap (\(KV _ v) -> coe1 v) DEnumMap <$> IM.minView m +minView (DEnumMap m) = bimap' (\(KV _ v) -> coe1 v) DEnumMap <$!> IM.minView m maxView :: DEnumMap k v -> Maybe (v a, DEnumMap k v) -maxView (DEnumMap m) = bimap (\(KV _ v) -> coe1 v) DEnumMap <$> IM.maxView m +maxView (DEnumMap m) = bimap' (\(KV _ v) -> coe1 v) DEnumMap <$!> IM.maxView m minViewWithKey :: Enum1 k => DEnumMap k v -> Maybe (DSum k v, DEnumMap k v) -minViewWithKey (DEnumMap m) = bimap kVToDSum DEnumMap <$> IM.minViewWithKey m +minViewWithKey (DEnumMap m) = bimap' kVToDSum DEnumMap <$!> IM.minViewWithKey m maxViewWithKey :: Enum1 k => DEnumMap k v -> Maybe (DSum k v, DEnumMap k v) -maxViewWithKey (DEnumMap m) = bimap kVToDSum DEnumMap <$> IM.maxViewWithKey m +maxViewWithKey (DEnumMap m) = bimap' kVToDSum DEnumMap <$!> IM.maxViewWithKey m -- * Helpers @@ -692,3 +694,9 @@ typeCheck2 _ i inf1 inf2 = Just Refl -> True Nothing -> False }}) (unsafeCoerce Refl) + +bimap' :: (a -> b) -> (c -> d) -> (a, c) -> (b, d) +bimap' f g (a, c) = + let !b = f a + !d = g c + in (b, d) -- cgit v1.2.3-70-g09d2