packages feed

to 1.0.0 → 1.1.0

raw patch · 4 files changed

+327/−40 lines, 4 filesdep +containersdep +gaugedep +hashabledep ~base

Dependencies added: containers, gauge, hashable, unordered-containers

Dependency ranges changed: base

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+# 1.1.0++* Added `toMap`, `toSet`, `toIntMap`, `toIntSet`, `toHashMap`, `toHashSet`.+ # 1.0.0  Initial version.
+ bench/Main.hs view
@@ -0,0 +1,102 @@+module Main (main) where++import qualified Data.Map.Lazy as ML+import qualified Data.IntMap.Lazy as IML+import qualified Data.Set as S+import qualified Data.IntSet as IS+import qualified Data.HashMap.Lazy as HML+import qualified Data.HashSet as HS+import Data.Text (Text, pack)+import Gauge++main :: IO ()+main = defaultMain+    [ bgroup "IntMap->Map" intMapToMapBench+    , bgroup "HashMap->Map" hashMapToMapBench+    , bgroup "IntSet->Set" intSetToSetBench+    , bgroup "HashSet->Set" hashSetToSetBench+    ]++----------------------------------------------------------------------------+-- IntMap->Map+----------------------------------------------------------------------------++intMapToMapBench :: [Benchmark]+intMapToMapBench =+    [ bench "foldr" $+          whnf (IML.foldrWithKey ML.insert mempty) sampleIntMap+    , bench "foldl'" $+          whnf (IML.foldlWithKey' (\m k v -> ML.insert k v m) mempty) sampleIntMap+    , bench "list" $+          whnf (ML.fromDistinctAscList . IML.toAscList) sampleIntMap+    ]++sampleIntMap :: IML.IntMap ()+sampleIntMap = IML.fromList [(i, ()) | i <- [1..1000 :: Int]]++----------------------------------------------------------------------------+-- HashMap->Map+----------------------------------------------------------------------------++hashMapToMapBench :: [Benchmark]+hashMapToMapBench =+    [ -- There was a possibility that for 'Int' the list variant would be+      -- faster because 'hash' is monotonic for 'Int', but the bencmarks+      -- show it's not faster+      bgroup "Int"+          [ bench "foldr" $+                whnf (HML.foldrWithKey ML.insert mempty) sampleHashMapInt+          , bench "foldl'" $+                whnf (HML.foldlWithKey' (\m k v -> ML.insert k v m) mempty) sampleHashMapInt+          , bench "list" $+                whnf (ML.fromList . HML.toList) sampleHashMapInt+          ]+    , bgroup "Text"+          [ bench "foldr" $+                whnf (HML.foldrWithKey ML.insert mempty) sampleHashMapText+          , bench "foldl'" $+                whnf (HML.foldlWithKey' (\m k v -> ML.insert k v m) mempty) sampleHashMapText+          , bench "list" $+                whnf (ML.fromList . HML.toList) sampleHashMapText+          ]+    ]++sampleHashMapInt :: HML.HashMap Int ()+sampleHashMapInt = HML.fromList [(i, ()) | i <- [1..1000 :: Int]]++sampleHashMapText :: HML.HashMap Text ()+sampleHashMapText = HML.fromList [(pack (show i), ()) | i <- [1..1000 :: Int]]++----------------------------------------------------------------------------+-- IntSet->Set+----------------------------------------------------------------------------++intSetToSetBench :: [Benchmark]+intSetToSetBench =+    [ bench "foldr" $+          whnf (IS.foldr S.insert mempty) sampleIntSet+    , bench "foldl'" $+          whnf (IS.foldl' (flip S.insert) mempty) sampleIntSet+    , bench "list" $+          whnf (S.fromDistinctAscList . IS.toAscList) sampleIntSet+    ]++sampleIntSet :: IS.IntSet+sampleIntSet = IS.fromList [1..1000 :: Int]++----------------------------------------------------------------------------+-- HashSet->Set+----------------------------------------------------------------------------++hashSetToSetBench :: [Benchmark]+hashSetToSetBench =+    [ bench "foldr" $+          whnf (HS.foldr S.insert mempty) sampleHashSet+    , bench "foldl'" $+          whnf (HS.foldl' (flip S.insert) mempty) sampleHashSet+    , bench "list" $+          whnf (S.fromList . HS.toList) sampleHashSet+    ]++sampleHashSet :: HS.HashSet Text+sampleHashSet = HS.fromList [pack (show i) | i <- [1..1000 :: Int]]
src/To.hs view
@@ -1,10 +1,33 @@+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-} +-- | Conversions to various things.+--+-- See the table of contents for the full list of types you can convert+-- into. module To (+    -- * Maps+    -- ** 'ML.Map'+    ToMap(..),+    -- ** 'HML.HashMap'+    ToHashMap(..),+    -- ** 'IML.IntMap'+    ToIntMap(..),++    -- * Sets+    -- ** 'S.Set'+    ToSet(..),+    -- ** 'HS.HashSet'+    ToHashSet(..),+    -- ** 'IS.IntSet'+    ToIntSet(..),+     -- * Strings and bytestrings     -- ** 'String'     ToString(..),@@ -28,6 +51,13 @@ where  import GHC.TypeLits (TypeError, ErrorMessage(..))+import Data.Hashable+import qualified Data.Map.Lazy as ML+import qualified Data.IntMap.Lazy as IML+import qualified Data.Set as S+import qualified Data.IntSet as IS+import qualified Data.HashMap.Lazy as HML+import qualified Data.HashSet as HS import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding.Error as T@@ -40,14 +70,152 @@ import qualified Data.ByteString.UTF8 as UTF8  ----------------------------------------------------------------------------+-- ToMap+----------------------------------------------------------------------------++class ToMap a k v | a -> k v, a k -> v, a v -> k where+    -- | Turn into a 'ML.Map'.+    toMap :: a -> ML.Map k v++-- | @[(k, v)] -> Map k v@+instance (kv ~ (k, v), Ord k) => ToMap [kv] k v where+    toMap = ML.fromList+    {-# INLINE toMap #-}++-- | @HashMap k v -> Map k v@+instance Ord k => ToMap (HML.HashMap k v) k v where+    toMap = HML.foldlWithKey' (\m k v -> ML.insert k v m) mempty+    {-# INLINE toMap #-}++-- | @IntMap v -> Map Int v@+instance ToMap (IML.IntMap v) Int v where+    toMap = ML.fromDistinctAscList . IML.toAscList+    {-# INLINE toMap #-}++----------------------------------------------------------------------------+-- ToSet+----------------------------------------------------------------------------++class ToSet a k | a -> k where+    -- | Turn into a 'S.Set'.+    toSet :: a -> S.Set k++-- | @[k] -> Set k@+instance Ord k => ToSet [k] k where+    toSet = S.fromList+    {-# INLINE toSet #-}++-- | @HashSet k -> Set k@+instance Ord k => ToSet (HS.HashSet k) k where+    toSet = HS.foldl' (flip S.insert) mempty+    {-# INLINE toSet #-}++-- | @IntSet -> Set Int@+instance ToSet IS.IntSet Int where+    toSet = S.fromDistinctAscList . IS.toAscList+    {-# INLINE toSet #-}++----------------------------------------------------------------------------+-- ToIntMap+----------------------------------------------------------------------------++class ToIntMap a v | a -> v where+    -- | Turn into an 'IML.IntMap'.+    toIntMap :: a -> IML.IntMap v++-- | @[(Int, v)] -> IntMap v@+instance (kv ~ (Int, v)) => ToIntMap [kv] v where+    toIntMap = IML.fromList+    {-# INLINE toIntMap #-}++-- | @Map Int v -> IntMap v@+instance ToIntMap (ML.Map Int v) v where+    toIntMap = IML.fromDistinctAscList . ML.toAscList+    {-# INLINE toIntMap #-}++-- | @HashMap Int v -> IntMap v@+instance ToIntMap (HML.HashMap Int v) v where+    toIntMap = HML.foldlWithKey' (\m k v -> IML.insert k v m) mempty+    {-# INLINE toIntMap #-}++----------------------------------------------------------------------------+-- ToIntSet+----------------------------------------------------------------------------++class ToIntSet a where+    -- | Turn into an 'IS.IntSet'.+    toIntSet :: a -> IS.IntSet++-- | @[Int] -> IntSet@+instance (k ~ Int) => ToIntSet [k] where+    toIntSet = IS.fromList+    {-# INLINE toIntSet #-}++-- | @Set Int -> IntSet@+instance ToIntSet (S.Set Int) where+    toIntSet = IS.fromDistinctAscList . S.toAscList+    {-# INLINE toIntSet #-}++-- | @HashSet Int -> IntSet@+instance ToIntSet (HS.HashSet Int) where+    toIntSet = HS.foldl' (flip IS.insert) mempty+    {-# INLINE toIntSet #-}++----------------------------------------------------------------------------+-- ToHashMap+----------------------------------------------------------------------------++class ToHashMap a k v | a -> k v, a k -> v, a v -> k where+    -- | Turn into a 'HML.HashMap'.+    toHashMap :: a -> HML.HashMap k v++-- | @[(k, v)] -> HashMap k v@+instance (kv ~ (k, v), Eq k, Hashable k) => ToHashMap [kv] k v where+    toHashMap = HML.fromList+    {-# INLINE toHashMap #-}++-- | @Map k v -> HashMap k v@+instance (Eq k, Hashable k) => ToHashMap (ML.Map k v) k v where+    toHashMap = ML.foldlWithKey' (\m k v -> HML.insert k v m) mempty+    {-# INLINE toHashMap #-}++-- | @IntMap v -> HashMap Int v@+instance ToHashMap (IML.IntMap v) Int v where+    toHashMap = IML.foldlWithKey' (\m k v -> HML.insert k v m) mempty+    {-# INLINE toHashMap #-}++----------------------------------------------------------------------------+-- ToHashSet+----------------------------------------------------------------------------++class ToHashSet a k | a -> k where+    -- | Turn into a 'HS.HashSet'.+    toHashSet :: a -> HS.HashSet k++-- | @[k] -> HashSet k@+instance (Eq k, Hashable k) => ToHashSet [k] k where+    toHashSet = HS.fromList+    {-# INLINE toHashSet #-}++-- | @Set k -> HashSet k@+instance (Eq k, Hashable k) => ToHashSet (S.Set k) k where+    toHashSet = S.foldl' (flip HS.insert) mempty+    {-# INLINE toHashSet #-}++-- | @IntSet -> HashSet Int@+instance ToHashSet IS.IntSet Int where+    toHashSet = IS.foldl' (flip HS.insert) mempty+    {-# INLINE toHashSet #-}++---------------------------------------------------------------------------- -- ToText ----------------------------------------------------------------------------  class ToText a where-    -- | Transforming to strict 'T.Text'.+    -- | Turn into strict 'T.Text'.     toText :: a -> T.Text --- | 'String'+-- | @String -> Text@ instance (a ~ Char) => ToText [a] where     toText = T.pack     {-# INLINE toText #-}@@ -60,12 +228,12 @@     toText = TL.toStrict . TB.toLazyText     {-# INLINE toText #-} --- | Use 'utf8ToText'.+-- | Use 'utf8ToText' instance TypeError (SpecifyDecoding BS.ByteString "utf8ToText") =>          ToText BS.ByteString where     toText = error "unreachable" --- | Use 'utf8ToText'.+-- | Use 'utf8ToText' instance TypeError (SpecifyDecoding BSL.ByteString "utf8ToText") =>          ToText BSL.ByteString where     toText = error "unreachable"@@ -75,10 +243,10 @@ ----------------------------------------------------------------------------  class ToLazyText a where-    -- | Transforming to lazy 'TL.Text'.+    -- | Turn into lazy 'TL.Text'.     toLazyText :: a -> TL.Text --- | 'String'+-- | @String -> Text@ instance (a ~ Char) => ToLazyText [a] where     toLazyText = TL.pack     {-# INLINE toLazyText #-}@@ -91,12 +259,12 @@     toLazyText = TB.toLazyText     {-# INLINE toLazyText #-} --- | Use 'utf8ToLazyText'.+-- | Use 'utf8ToLazyText' instance TypeError (SpecifyDecoding BS.ByteString "utf8ToLazyText") =>          ToLazyText BS.ByteString where     toLazyText = error "unreachable" --- | Use 'utf8ToLazyText'.+-- | Use 'utf8ToLazyText' instance TypeError (SpecifyDecoding BSL.ByteString "utf8ToLazyText") =>          ToLazyText BSL.ByteString where     toLazyText = error "unreachable"@@ -106,10 +274,10 @@ ----------------------------------------------------------------------------  class ToTextBuilder a where-    -- | Transforming to text 'TB.Builder'.+    -- | Turn into text 'TB.Builder'.     toTextBuilder :: a -> TB.Builder --- | 'String'+-- | @String -> Text@ instance (a ~ Char) => ToTextBuilder [a] where     toTextBuilder = TB.fromString     {-# INLINE toTextBuilder #-}@@ -122,12 +290,12 @@     toTextBuilder = TB.fromLazyText     {-# INLINE toTextBuilder #-} --- | Use 'utf8ToTextBuilder'.+-- | Use 'utf8ToTextBuilder' instance TypeError (SpecifyDecoding BS.ByteString "utf8ToTextBuilder") =>          ToTextBuilder BS.ByteString where     toTextBuilder = error "unreachable" --- | Use 'utf8ToTextBuilder'.+-- | Use 'utf8ToTextBuilder' instance TypeError (SpecifyDecoding BSL.ByteString "utf8ToTextBuilder") =>          ToTextBuilder BSL.ByteString where     toTextBuilder = error "unreachable"@@ -137,7 +305,7 @@ ----------------------------------------------------------------------------  class ToString a where-    -- | Transforming to 'String'.+    -- | Turn into 'String'.     toString :: a -> String  instance ToString T.Text where@@ -152,12 +320,12 @@     toString = TL.unpack . TB.toLazyText     {-# INLINE toString #-} --- | Use 'utf8ToString'.+-- | Use 'utf8ToString' instance TypeError (SpecifyDecoding BS.ByteString "utf8ToString") =>          ToString BS.ByteString where     toString = error "unreachable" --- | Use 'utf8ToString'.+-- | Use 'utf8ToString' instance TypeError (SpecifyDecoding BSL.ByteString "utf8ToString") =>          ToString BSL.ByteString where     toString = error "unreachable"@@ -167,30 +335,29 @@ ----------------------------------------------------------------------------  class ToByteString a where-    -- | Transforming to strict 'BS.ByteString'.+    -- | Turn into strict 'BS.ByteString'.     toByteString :: a -> BS.ByteString --- | Use 'toUtf8ByteString'.+-- | Use 'toUtf8ByteString' instance TypeError (SpecifyEncoding T.Text "toUtf8ByteString") =>          ToByteString T.Text where     toByteString = error "unreachable" --- | Use 'toUtf8ByteString'.+-- | Use 'toUtf8ByteString' instance TypeError (SpecifyEncoding TL.Text "toUtf8ByteString") =>          ToByteString TL.Text where     toByteString = error "unreachable" --- | Use 'toUtf8ByteString'.+-- | Use 'toUtf8ByteString' instance TypeError (SpecifyEncoding TB.Builder "toUtf8ByteString") =>          ToByteString TB.Builder where     toByteString = error "unreachable" --- | Use 'toUtf8ByteString'.+-- | Use 'toUtf8ByteString' instance (a ~ Char, TypeError (SpecifyEncoding String "toUtf8ByteString")) =>          ToByteString [a] where     toByteString = error "unreachable" --- | Use 'toUtf8ByteString'. instance ToByteString BSL.ByteString where     toByteString = BSL.toStrict     {-# INLINE toByteString #-}@@ -200,25 +367,25 @@ ----------------------------------------------------------------------------  class ToLazyByteString a where-    -- | Transforming to lazy 'BSL.ByteString'.+    -- | Turn into lazy 'BSL.ByteString'.     toLazyByteString :: a -> BSL.ByteString --- | Use 'toUtf8LazyByteString'.+-- | Use 'toUtf8LazyByteString' instance TypeError (SpecifyEncoding T.Text "toUtf8LazyByteString") =>          ToLazyByteString T.Text where     toLazyByteString = error "unreachable" --- | Use 'toUtf8LazyByteString'.+-- | Use 'toUtf8LazyByteString' instance TypeError (SpecifyEncoding TL.Text "toUtf8LazyByteString") =>          ToLazyByteString TL.Text where     toLazyByteString = error "unreachable" --- | Use 'toUtf8LazyByteString'.+-- | Use 'toUtf8LazyByteString' instance TypeError (SpecifyEncoding TB.Builder "toUtf8LazyByteString") =>          ToLazyByteString TB.Builder where     toLazyByteString = error "unreachable" --- | Use 'toUtf8LazyByteString'.+-- | Use 'toUtf8LazyByteString' instance (a ~ Char, TypeError (SpecifyEncoding String "toUtf8LazyByteString")) =>          ToLazyByteString [a] where     toLazyByteString = error "unreachable"@@ -232,7 +399,7 @@ ----------------------------------------------------------------------------  class Utf8ToString a where-    -- | Decode UTF8-encoded text to a 'String'.+    -- | Decode UTF8-encoded text into 'String'.     --     -- Malformed characters are replaced by @U+FFFD@ (the Unicode     -- replacement character).@@ -251,7 +418,7 @@ ----------------------------------------------------------------------------  class Utf8ToText a where-    -- | Decode UTF8-encoded text to a strict 'T.Text'.+    -- | Decode UTF8-encoded text into strict 'T.Text'.     --     -- Malformed characters are replaced by @U+FFFD@ (the Unicode     -- replacement character).@@ -270,7 +437,7 @@ ----------------------------------------------------------------------------  class Utf8ToLazyText a where-    -- | Decode UTF8-encoded text to a lazy 'TL.Text'.+    -- | Decode UTF8-encoded text into lazy 'TL.Text'.     --     -- Malformed characters are replaced by @U+FFFD@ (the Unicode     -- replacement character).@@ -289,7 +456,7 @@ ----------------------------------------------------------------------------  class Utf8ToTextBuilder a where-    -- | Decode UTF8-encoded text to a text 'TB.Builder'.+    -- | Decode UTF8-encoded text into text 'TB.Builder'.     --     -- Malformed characters are replaced by @U+FFFD@ (the Unicode     -- replacement character).@@ -308,7 +475,7 @@ ----------------------------------------------------------------------------  class ToUtf8ByteString a where-    -- | UTF8-encode text to a 'BS.ByteString'.+    -- | UTF8-encode text into 'BS.ByteString'.     toUtf8ByteString :: a -> BS.ByteString  instance ToUtf8ByteString T.Text where@@ -323,7 +490,7 @@     toUtf8ByteString = T.encodeUtf8 . TL.toStrict . TB.toLazyText     {-# INLINE toUtf8ByteString #-} --- | 'String'+-- | @String -> ByteString@ instance (a ~ Char) => ToUtf8ByteString [a] where     toUtf8ByteString = UTF8.fromString     {-# INLINE toUtf8ByteString #-}@@ -333,7 +500,7 @@ ----------------------------------------------------------------------------  class ToUtf8LazyByteString a where-    -- | UTF8-encode text to a lazy 'BSL.ByteString'.+    -- | UTF8-encode text into lazy 'BSL.ByteString'.     toUtf8LazyByteString :: a -> BSL.ByteString  instance ToUtf8LazyByteString T.Text where@@ -348,7 +515,7 @@     toUtf8LazyByteString = TL.encodeUtf8 . TB.toLazyText     {-# INLINE toUtf8LazyByteString #-} --- | 'String'+-- | @String -> ByteString@ instance (a ~ Char) => ToUtf8LazyByteString [a] where     toUtf8LazyByteString = UTF8L.fromString     {-# INLINE toUtf8LazyByteString #-}
to.cabal view
@@ -1,5 +1,5 @@ name:                to-version:             1.0.0+version:             1.1.0 synopsis:            Simple, safe, boring type conversions description:   `to` contains type conversions for popular Haskell types. All provided@@ -23,12 +23,26 @@  library   exposed-modules:     To-  build-depends:-    base >=4.9 && <5,-    text,-    bytestring,-    utf8-string+  build-depends:       base >=4.9 && <5,+                       bytestring,+                       containers,+                       unordered-containers,+                       hashable,+                       text,+                       utf8-string   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -Wall                        -Wno-unticked-promoted-constructors++benchmark benches+  type:                exitcode-stdio-1.0+  hs-source-dirs:      bench+  main-is:             Main.hs+  build-depends:       base+                     , containers+                     , unordered-containers+                     , text+                     , gauge+  default-language:    Haskell2010+  ghc-options:         -Wall