monoidmap-internal 0.3.0.0 → 0.4.0.0
raw patch · 10 files changed
+404/−198 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.MonoidMap.Internal: NonNullMap :: Map k (NonNull v) -> NonNullMap k v
- Data.MonoidMap.Internal: applyNonNull :: (v -> a) -> NonNull v -> a
- Data.MonoidMap.Internal: applyNonNull2 :: (v1 -> v2 -> a) -> NonNull v1 -> NonNull v2 -> a
- Data.MonoidMap.Internal: data NonNull v
- Data.MonoidMap.Internal: fromMap :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_mapMaybe :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_map_filter :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_map_filter_if_any_null :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMap_filter :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMap_filter_if_any_null :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMap_mapMaybe :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromNonNullMap :: Map k (NonNull v) -> Map k v
- Data.MonoidMap.Internal: instance (Control.DeepSeq.NFData k, Control.DeepSeq.NFData v) => Control.DeepSeq.NFData (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (NoThunks.Class.NoThunks k, NoThunks.Class.NoThunks v) => NoThunks.Class.NoThunks (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance Control.DeepSeq.NFData v => Control.DeepSeq.NFData (Data.MonoidMap.Internal.NonNull v)
- Data.MonoidMap.Internal: instance Data.Bifoldable.Bifoldable Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance Data.Foldable.Foldable (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: instance Data.Functor.Classes.Eq2 Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance Data.Functor.Classes.Show2 Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance GHC.Classes.Eq k => Data.Functor.Classes.Eq1 (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: instance GHC.Show.Show k => Data.Functor.Classes.Show1 (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: maybeNonNull :: MonoidNull v => v -> Maybe (NonNull v)
- Data.MonoidMap.Internal: newtype NonNullMap k v
+ Data.MonoidMap.Internal.NonNull: apply :: (v -> a) -> NonNull v -> a
+ Data.MonoidMap.Internal.NonNull: apply2 :: (v1 -> v2 -> a) -> NonNull v1 -> NonNull v2 -> a
+ Data.MonoidMap.Internal.NonNull: data NonNull v
+ Data.MonoidMap.Internal.NonNull: nonNull :: MonoidNull v => v -> Maybe (NonNull v)
+ Data.MonoidMap.Internal.NonNull: unwrap :: NonNull v -> v
+ Data.MonoidMap.Internal.NonNullMap: NonNullMap :: Map k (NonNull v) -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: fromMap :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap: newtype NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: toMap :: NonNullMap k v -> Map k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_filter :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_filter_if_any_null :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_mapMaybe :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_mapMaybe :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_map_filter :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_map_filter_if_any_null :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
Files
- CHANGELOG.md +31/−0
- components/monoidmap-internal-benchmark/Main.hs +3/−1
- components/monoidmap-internal/Data/MonoidMap/Internal.hs +0/−195
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNull.hs +49/−0
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNull/Unsafe.hs +60/−0
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap.hs +68/−0
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMap.hs +57/−0
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMapWith.hs +51/−0
- components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/Unsafe.hs +77/−0
- monoidmap-internal.cabal +8/−2
CHANGELOG.md view
@@ -1,3 +1,34 @@+# 0.4.0.0++- Revised the module structure of the package, replacing the+ `Data.MonoidMap.Internal` module with the following modules:++ - `Data.MonoidMap.Internal.NonNull`+ - `Data.MonoidMap.Internal.NonNullMap`+ - `Data.MonoidMap.Internal.NonNullMap.FromMap`+ - `Data.MonoidMap.Internal.NonNullMap.FromMapWith`++ The new structure has the following aims:++ - To confine the data constructor of `NonNull` to two small private+ modules, making the code that maintains the `NonNull` invariant+ a little easier to audit.++ - To dedicate each public module to a single type, with functions named+ for qualified import. Several functions have been renamed accordingly:+ for example, `maybeNonNull` is now `NonNull.nonNull`, and+ `fromNonNullMap` is now `NonNullMap.toMap`.++ - To move the alternative `fromMap*` and `fromMapWith*` implementations,+ which exist only for benchmarking, into their own modules, so that+ they no longer clutter the main API.++- Changed `fromMap`, `fromMapWith`, and `toMap` to accept or return values+ of type `NonNullMap k v` instead of `Map k (NonNull v)`.++- Added documentation for the `NonNull` and `NonNullMap` types and their+ functions.+ # 0.3.0.0 - Moved the `MonoidMap` type, its instances, and all of its functions to
components/monoidmap-internal-benchmark/Main.hs view
@@ -36,7 +36,9 @@ ( Benchmark, bcompare, bench, bgroup, defaultMain, nf ) import qualified Data.Map.Strict as OMap-import qualified Data.MonoidMap.Internal as MMap+import qualified Data.MonoidMap.Internal.NonNullMap as MMap+import qualified Data.MonoidMap.Internal.NonNullMap.FromMap as MMap+import qualified Data.MonoidMap.Internal.NonNullMap.FromMapWith as MMap main :: IO () main = do
− components/monoidmap-internal/Data/MonoidMap/Internal.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE RoleAnnotations #-}-{- HLINT ignore "Avoid lambda" -}-{- HLINT ignore "Avoid lambda using `infix`" -}-{- HLINT ignore "Redundant bracket" -}-{- HLINT ignore "Use camelCase" -}---- |--- Copyright: © 2022–2026 Jonathan Knowles--- License: Apache-2.0------ Provides /internal/ support for the @monoidmap@ package.------ This module defines the 'NonNull' type of values that are not 'C.null',--- and functions for constructing maps of 'NonNull' values from ordinary maps.----module Data.MonoidMap.Internal- (- -- * Types- NonNull- , NonNullMap (..)-- -- * Non-null values- , maybeNonNull- , applyNonNull- , applyNonNull2-- -- * Non-null maps- , fromNonNullMap-- -- * Construction- , fromMap- , fromMapWith-- -- ** Implementations- , fromMap_filter- , fromMap_filter_if_any_null- , fromMap_mapMaybe- , fromMapWith_mapMaybe- , fromMapWith_map_filter- , fromMapWith_map_filter_if_any_null- )- where--import Prelude--import Control.DeepSeq- ( NFData )-import Data.Bifoldable- ( Bifoldable )-import Data.Coerce- ( coerce )-import Data.Functor.Classes- ( Eq1, Eq2, Show1, Show2 )-import Data.Map.Strict- ( Map )-import Data.Monoid.Null- ( MonoidNull )-import NoThunks.Class- ( NoThunks )--import qualified Data.Foldable as F-import qualified Data.Map.Strict as Map-import qualified Data.Monoid.Null as C------------------------------------------------------------------------------------- Non-null values-----------------------------------------------------------------------------------newtype NonNull v = UnsafeNonNull v- deriving newtype NFData---- Without an explicit type role annotation, the following role would be--- inferred:------ type role NonNull representational------ However, the validity of a 'NonNull' value depends on a property of its--- type: its 'mempty' value. A representational role would allow users to--- coerce between types with the same representation but different 'mempty'--- values, even without access to the 'NonNull' constructor.------ For example, users could coerce a 'NonNull' ('Sum' 'Int') to a 'NonNull'--- ('Product' 'Int'), and thereby construct a 'NonNull' value that is 'mempty'.------ So we must instead choose a nominal role.----type role NonNull nominal--maybeNonNull :: MonoidNull v => v -> Maybe (NonNull v)-maybeNonNull !v- | C.null v = Nothing- | otherwise = Just (UnsafeNonNull v)-{-# INLINE maybeNonNull #-}--applyNonNull :: (v -> a) -> (NonNull v -> a)-applyNonNull = coerce-{-# INLINE applyNonNull #-}--applyNonNull2 :: (v1 -> v2 -> a) -> (NonNull v1 -> NonNull v2 -> a)-applyNonNull2 = coerce-{-# INLINE applyNonNull2 #-}--fromNonNullMap :: Map k (NonNull v) -> Map k v-fromNonNullMap = coerce-{-# INLINE fromNonNullMap #-}---- | /Unsafely/ converts an ordinary map into a map of non-null values.------ This function /expects/ but does /not/ check that no value in the given map--- is 'C.null'. It must only be applied to maps that satisfy this condition.----unsafeToNonNullMap :: Map k v -> Map k (NonNull v)-unsafeToNonNullMap = coerce-{-# INLINE unsafeToNonNullMap #-}------------------------------------------------------------------------------------- Non-null maps------------------------------------------------------------------------------------- A map of non-null values.------ Types with the same representation as 'NonNullMap' (such as 'MonoidMap')--- can derive their instances via this type, without needing access to the--- constructor of 'NonNull'.----newtype NonNullMap k v = NonNullMap (Map k (NonNull v))- deriving (Eq, Show, NFData, NoThunks) via Map k v- deriving (Eq1, Show1, Foldable) via Map k- deriving (Eq2, Show2, Bifoldable) via Map---- Strictly speaking, this type role annotation is redundant, as:------ - The type parameter 'k' already has a nominal role inherited from 'Map'.--- - The type parameter 'v' already has a nominal role inherited from 'NonNull'.------ But we reassert these roles here, so that they cannot be silently weakened--- by a future change to the representation of 'NonNullMap'.----type role NonNullMap nominal nominal------------------------------------------------------------------------------------- Construction------------------------------------------------------------------------------------- | Constructs a map of non-null values from an ordinary 'Map', removing all--- 'C.null' values.------ This function selects which of the @fromMap_*@ implementations below is used--- by the public @fromMap@ function of the @monoidmap@ package.----fromMap :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap = fromMap_filter_if_any_null-{-# INLINE fromMap #-}--fromMap_filter :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_filter = unsafeToNonNullMap . Map.filter (\(!v) -> not (C.null v))-{-# INLINABLE fromMap_filter #-}--fromMap_filter_if_any_null :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_filter_if_any_null m- | F.any (\(!v) -> C.null v) m =- unsafeToNonNullMap $ Map.filter (\(!v) -> not (C.null v)) m- | otherwise =- unsafeToNonNullMap m-{-# INLINABLE fromMap_filter_if_any_null #-}--fromMap_mapMaybe :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_mapMaybe = Map.mapMaybe maybeNonNull-{-# INLINABLE fromMap_mapMaybe #-}---- | Constructs a map of non-null values from an ordinary 'Map', applying the--- given function to all values, and removing all 'C.null' values.------ This function selects which of the @fromMapWith_*@ implementations below is--- used by the public @fromMapWith@ function of the @monoidmap@ package.----fromMapWith- :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith = fromMapWith_mapMaybe-{-# INLINE fromMapWith #-}--fromMapWith_mapMaybe- :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_mapMaybe f = Map.mapMaybe (maybeNonNull . f)-{-# INLINABLE fromMapWith_mapMaybe #-}--fromMapWith_map_filter- :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_map_filter f = fromMap_filter . Map.map f-{-# INLINABLE fromMapWith_map_filter #-}--fromMapWith_map_filter_if_any_null- :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_map_filter_if_any_null f = fromMap_filter_if_any_null . Map.map f-{-# INLINABLE fromMapWith_map_filter_if_any_null #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNull.hs view
@@ -0,0 +1,49 @@+-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides the 'NonNull' type and related functions.+--+-- This module is intended to be imported qualified:+--+-- @+-- import Data.MonoidMap.Internal.NonNull (NonNull)+-- import Data.MonoidMap.Internal.NonNull qualified as NonNull+-- @+--+module Data.MonoidMap.Internal.NonNull+ (+ -- * Type+ NonNull++ -- * Construction+ , nonNull++ -- * Deconstruction+ , unwrap++ -- * Function application+ , apply+ , apply2+ )+ where++import Prelude hiding+ ( null )++import Data.Monoid.Null+ ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull.Unsafe+ ( NonNull, nonNull, unwrap )++-- | Applies a function on ordinary values to a 'NonNull' value.+--+apply :: (v -> a) -> (NonNull v -> a)+apply f = f . unwrap+{-# INLINE apply #-}++-- | Applies a binary function on ordinary values to two 'NonNull' values.+--+apply2 :: (v1 -> v2 -> a) -> (NonNull v1 -> NonNull v2 -> a)+apply2 f v1 v2 = f (unwrap v1) (unwrap v2)+{-# INLINE apply2 #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNull/Unsafe.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE RoleAnnotations #-}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Defines the 'NonNull' type, together with the primitive operations on+-- 'NonNull' values that need access to its data constructor.+--+module Data.MonoidMap.Internal.NonNull.Unsafe+ ( NonNull (UnsafeNonNull)+ , nonNull+ , unwrap+ )+ where++import Prelude hiding+ ( null )++import Control.DeepSeq+ ( NFData )+import Data.Monoid.Null+ ( MonoidNull (null) )++-- | A value that is not 'null'.+--+newtype NonNull v = UnsafeNonNull v+ deriving newtype NFData++-- Without an explicit type role annotation, the following role would be+-- inferred:+--+-- type role NonNull representational+--+-- However, the validity of a 'NonNull' value depends on a property of its+-- type: its 'mempty' value. A representational role would allow users to+-- coerce between types with the same representation but different 'mempty'+-- values, even without access to the 'NonNull' constructor.+--+-- For example, users could coerce a 'NonNull' ('Sum' 'Int') to a 'NonNull'+-- ('Product' 'Int'), and thereby construct a 'NonNull' value that is 'mempty'.+--+-- So we must instead choose a nominal role.+--+type role NonNull nominal++-- | Converts a value into a 'NonNull' value, returning 'Nothing' if the+-- value is 'null'.+--+nonNull :: MonoidNull v => v -> Maybe (NonNull v)+nonNull !v+ | null v = Nothing+ | otherwise = Just (UnsafeNonNull v)+{-# INLINE nonNull #-}++-- | Extracts the value from a 'NonNull' value.+--+unwrap :: NonNull v -> v+unwrap (UnsafeNonNull v) = v+{-# INLINE unwrap #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap.hs view
@@ -0,0 +1,68 @@+-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides the 'NonNullMap' type and related functions.+--+-- This module is intended to be imported qualified:+--+-- @+-- import Data.MonoidMap.Internal.NonNullMap (NonNullMap (..))+-- import Data.MonoidMap.Internal.NonNullMap qualified as NonNullMap+-- @+--+module Data.MonoidMap.Internal.NonNullMap+ (+ -- * Type+ NonNullMap (..)++ -- * Construction+ , fromMap+ , fromMapWith++ -- * Deconstruction+ , toMap+ )+ where++import Prelude hiding+ ( null )++import Data.Map.Strict+ ( Map )+import Data.Monoid.Null+ ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull+ ( NonNull )+import Data.MonoidMap.Internal.NonNullMap.FromMap+ ( fromMap_filter_if_any_null )+import Data.MonoidMap.Internal.NonNullMap.FromMapWith+ ( fromMapWith_mapMaybe )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+ ( NonNullMap (..), toMap )++--------------------------------------------------------------------------------+-- Construction+--------------------------------------------------------------------------------++-- | Constructs a 'NonNullMap' from an ordinary 'Map', removing all+-- 'null' values.+--+-- This function selects which of the implementations in+-- "Data.MonoidMap.Internal.NonNullMap.FromMap" is used by the public @fromMap@+-- function of the @monoidmap@ package.+--+fromMap :: MonoidNull v => Map k v -> NonNullMap k v+fromMap = fromMap_filter_if_any_null+{-# INLINE fromMap #-}++-- | Constructs a 'NonNullMap' from an ordinary 'Map', applying the given+-- function to all values, and removing all 'null' values.+--+-- This function selects which of the implementations in+-- "Data.MonoidMap.Internal.NonNullMap.FromMapWith" is used by the public+-- @fromMapWith@ function of the @monoidmap@ package.+--+fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith = fromMapWith_mapMaybe+{-# INLINE fromMapWith #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMap.hs view
@@ -0,0 +1,57 @@+{- HLINT ignore "Avoid lambda" -}+{- HLINT ignore "Avoid lambda using `infix`" -}+{- HLINT ignore "Redundant bracket" -}+{- HLINT ignore "Use camelCase" -}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides alternative implementations of @fromMap@, which constructs a+-- map of 'NonNull' values from an ordinary map.+--+-- These implementations are exported so that they can be benchmarked against+-- one another.+--+module Data.MonoidMap.Internal.NonNullMap.FromMap+ ( fromMap_filter+ , fromMap_filter_if_any_null+ , fromMap_mapMaybe+ )+ where++import Prelude hiding+ ( null )++import Data.Map.Strict+ ( Map )+import Data.Monoid.Null+ ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull+ ( NonNull, nonNull )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+ ( NonNullMap (..)+ , unsafeFromMap+ )++import qualified Data.Foldable as F+import qualified Data.Map.Strict as Map++fromMap_filter+ :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_filter = unsafeFromMap . Map.filter (\(!v) -> not (null v))+{-# INLINABLE fromMap_filter #-}++fromMap_filter_if_any_null+ :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_filter_if_any_null m+ | F.any (\(!v) -> null v) m =+ unsafeFromMap $ Map.filter (\(!v) -> not (null v)) m+ | otherwise =+ unsafeFromMap m+{-# INLINABLE fromMap_filter_if_any_null #-}++fromMap_mapMaybe+ :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_mapMaybe = NonNullMap . Map.mapMaybe nonNull+{-# INLINABLE fromMap_mapMaybe #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMapWith.hs view
@@ -0,0 +1,51 @@+{- HLINT ignore "Use camelCase" -}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides alternative implementations of @fromMapWith@, which constructs a+-- map of 'NonNull' values from an ordinary map, applying a function to all+-- values.+--+-- These implementations are exported so that they can be benchmarked against+-- one another.+--+module Data.MonoidMap.Internal.NonNullMap.FromMapWith+ ( fromMapWith_mapMaybe+ , fromMapWith_map_filter+ , fromMapWith_map_filter_if_any_null+ )+ where++import Prelude++import Data.Map.Strict+ ( Map )+import Data.Monoid.Null+ ( MonoidNull )+import Data.MonoidMap.Internal.NonNull+ ( NonNull, nonNull )+import Data.MonoidMap.Internal.NonNullMap.FromMap+ ( fromMap_filter+ , fromMap_filter_if_any_null+ )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+ ( NonNullMap (..) )++import qualified Data.Map.Strict as Map++fromMapWith_mapMaybe+ :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_mapMaybe f = NonNullMap . Map.mapMaybe (nonNull . f)+{-# INLINABLE fromMapWith_mapMaybe #-}++fromMapWith_map_filter+ :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_map_filter f = fromMap_filter . Map.map f+{-# INLINABLE fromMapWith_map_filter #-}++fromMapWith_map_filter_if_any_null+ :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_map_filter_if_any_null f = fromMap_filter_if_any_null . Map.map f+{-# INLINABLE fromMapWith_map_filter_if_any_null #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/Unsafe.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE RoleAnnotations #-}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Defines the 'NonNullMap' type, together with the primitive operations on+-- 'NonNullMap' that need access to the data constructor of 'NonNull'.+--+module Data.MonoidMap.Internal.NonNullMap.Unsafe+ ( NonNullMap (..)+ , toMap+ , unsafeFromMap+ )+ where++import Prelude++import Control.DeepSeq+ ( NFData )+import Data.Bifoldable+ ( Bifoldable )+import Data.Coerce+ ( coerce )+import Data.Functor.Classes+ ( Eq1, Eq2, Show1, Show2 )+import Data.Map.Strict+ ( Map )+import Data.MonoidMap.Internal.NonNull.Unsafe+ ( NonNull (UnsafeNonNull) )+import NoThunks.Class+ ( NoThunks )++-- | A map of 'NonNull' values.+--+-- Other types with the same representation (such as @MonoidMap@ from the+-- @monoidmap@ package) can derive instances via this type, without access+-- to the data constructor of 'NonNull'.+--+newtype NonNullMap k v = NonNullMap (Map k (NonNull v))+ --+ -- Here we take great care to only derive instances that consume values.+ --+ -- It's risky to derive an instance that produces values, as the derived+ -- instance may not necessarily respect the 'NonNull' invariant.+ --+ -- For example, the 'Read' instance for 'Map', given appropriate input,+ -- will quite happily produce maps with 'mempty' values.+ --+ deriving (Eq, Show, NFData, NoThunks) via Map k v+ deriving (Eq1, Show1, Foldable) via Map k+ deriving (Eq2, Show2, Bifoldable) via Map++-- Strictly speaking, this type role annotation is redundant, as:+--+-- - The type parameter 'k' already has a nominal role inherited from 'Map'.+-- - The type parameter 'v' already has a nominal role inherited from 'NonNull'.+--+-- But we reassert these roles here, so that they cannot be silently weakened+-- by a future change to the representation of 'NonNullMap'.+--+type role NonNullMap nominal nominal++-- | Converts a 'NonNullMap' into an ordinary map.+--+toMap :: NonNullMap k v -> Map k v+toMap = coerce+{-# INLINE toMap #-}++-- | /Unsafely/ converts an ordinary map into a 'NonNullMap'.+--+-- This function /expects/ but does /not/ check that no value in the given map+-- is null. It must only be applied to maps that satisfy this condition.+--+unsafeFromMap :: Map k v -> NonNullMap k v+unsafeFromMap = coerce+{-# INLINE unsafeFromMap #-}
monoidmap-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: monoidmap-internal-version: 0.3.0.0+version: 0.4.0.0 homepage: https://github.com/jonathanknowles/monoidmap/tree/HEAD/packages/monoidmap-internal bug-reports: https://github.com/jonathanknowles/monoidmap/issues license: Apache-2.0@@ -65,7 +65,13 @@ hs-source-dirs: components/monoidmap-internal exposed-modules:- Data.MonoidMap.Internal+ Data.MonoidMap.Internal.NonNull+ Data.MonoidMap.Internal.NonNullMap+ Data.MonoidMap.Internal.NonNullMap.FromMap+ Data.MonoidMap.Internal.NonNullMap.FromMapWith+ other-modules:+ Data.MonoidMap.Internal.NonNull.Unsafe+ Data.MonoidMap.Internal.NonNullMap.Unsafe default-language: Haskell2010