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 +4/−0
- bench/Main.hs +102/−0
- src/To.hs +201/−34
- to.cabal +20/−6
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