on main help sign in
[#6] Add README, refresh docs, refactor, add hlint (#18)

* [#6] Add README, refresh docs, refactor, add hlint * Fix after review

commit75b6a57f20cc3a0cc4e488cbd39fcfc1cdeff9af authorVeronika Romashkina <vrom911@gmail.com> dateMon 9 Jul 2018, 12:59 (8 years ago) parente346251
12 files changed+86−76
.hlint.yaml+6 README.md+26−1 benchmark/CacheMap.hs+5−1 benchmark/OptimalVector.hs+5−1 benchmark/Vector.hs+5−1 internal/Data/TypeRep/CacheMap.hs+30−15 internal/Data/TypeRep/OptimalVector.hs+3−6 internal/Data/TypeRep/Vector.hs−1 src/Data/TypeRep/Map.hs+2 test/Test/TypeRep/CacheMap.hs+2−2 test/Test/TypeRep/Vector.hs+1−24 test/Test/TypeRep/VectorOpt.hs+1−24
.hlint.yamlnew file+6
@@ -0,0 +1,6 @@
1+- ignore: {name: "Use camelCase"}
2+
3+- arguments:
4+ - -XTypeApplications
5+
6+- warn: {name: "Use explicit module export list"}
README.md+26−1
@@ -1,5 +1,30 @@
11# typerep-map
22
33[![Hackage](https://img.shields.io/hackage/v/typerep-map.svg)](https://hackage.haskell.org/package/typerep-map)
4−[![Build status](https://secure.travis-ci.org/vrom911/typerep-map.svg)](https://travis-ci.org/vrom911/typerep-map)
4+[![Build status](https://secure.travis-ci.org/kowainik/typerep-map.svg)](https://travis-ci.org/kowainik/typerep-map)
5+[![Stackage LTS](http://stackage.org/package/typerep-map/badge/lts)](http://stackage.org/lts/package/typerep-map)
6+[![Stackage Nightly](http://stackage.org/package/typerep-map/badge/nightly)](http://stackage.org/nightly/package/typerep-map)
57[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/vrom911/typerep-map/blob/master/LICENSE)
8+
9+`typerep-map` introduces `TypeRepMap` — data structure like [`Map`](http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#t:Map), but where types serve as keys, and values have the types specified in the corresponding key spots.
10+
11+```haskell
12+ghci> let typeRepMap = insert (Identity True) $ insert (Identity (42 :: Int)) empty
13+
14+ghci> size typeRepMap
15+2
16+
17+ghci> let res = lookup typeRepMap
18+
19+ghci> res :: Maybe (Identity Int)
20+Just (Identity 42)
21+
22+ghci> res :: Maybe (Identity Bool)
23+Just (Identity True)
24+
25+ghci> res :: Maybe (Identity String)
26+Nothing
27+
28+ghci> lookup (insert (Identity "hello") typeRepMap) :: Maybe (Identity String)
29+Just (Identity "hello")
30+```
benchmark/CacheMap.hs+5−1
@@ -46,7 +46,11 @@ tenLookups tmap = (lp, lp, lp, lp, lp, lp, lp, lp)
4646bigMap :: TypeRepMap (Proxy :: Nat -> *)
4747bigMap = fromList $ buildBigMap 10000 (Proxy :: Proxy 0) []
4848
49−buildBigMap :: forall a . (KnownNat a) => Int -> Proxy (a :: Nat) -> [TF (Proxy :: Nat -> *)] -> [TF (Proxy :: Nat -> *)]
49+buildBigMap :: forall a . (KnownNat a)
50+ => Int
51+ -> Proxy (a :: Nat)
52+ -> [TF (Proxy :: Nat -> *)]
53+ -> [TF (Proxy :: Nat -> *)]
5054buildBigMap 1 x = (TF x :)
5155buildBigMap n x = (TF x :) . buildBigMap (n - 1) (Proxy :: Proxy (a + 1))
5256
benchmark/OptimalVector.hs+5−1
@@ -47,7 +47,11 @@ tenLookups tmap = (lp, lp, lp, lp, lp, lp, lp, lp)
4747bigMap :: TypeRepMap (Proxy :: Nat -> *)
4848bigMap = fromList $ buildBigMap 10000 (Proxy :: Proxy 0) []
4949
50−buildBigMap :: forall a . (KnownNat a) => Int -> Proxy (a :: Nat) -> [TF (Proxy :: Nat -> *)] -> [TF (Proxy :: Nat -> *)]
50+buildBigMap :: forall a . (KnownNat a)
51+ => Int
52+ -> Proxy (a :: Nat)
53+ -> [TF (Proxy :: Nat -> *)]
54+ -> [TF (Proxy :: Nat -> *)]
5155buildBigMap 1 x = (TF x :)
5256buildBigMap n x = (TF x :) . buildBigMap (n - 1) (Proxy :: Proxy (a + 1))
5357
benchmark/Vector.hs+5−1
@@ -47,7 +47,11 @@ tenLookups tmap = (lp, lp, lp, lp, lp, lp, lp, lp)
4747bigMap :: TypeRepVector (Proxy :: Nat -> *)
4848bigMap = fromList $ buildBigMap 10000 (Proxy :: Proxy 0) []
4949
50−buildBigMap :: forall a . (KnownNat a) => Int -> Proxy (a :: Nat) -> [TF (Proxy :: Nat -> *)] -> [TF (Proxy :: Nat -> *)]
50+buildBigMap :: forall a . (KnownNat a)
51+ => Int
52+ -> Proxy (a :: Nat)
53+ -> [TF (Proxy :: Nat -> *)]
54+ -> [TF (Proxy :: Nat -> *)]
5155buildBigMap 1 x = (TF x :)
5256buildBigMap n x = (TF x :) . buildBigMap (n - 1) (Proxy :: Proxy (a + 1))
5357
internal/Data/TypeRep/CacheMap.hs+30−15
@@ -46,15 +46,18 @@ import qualified Data.IntMap.Strict as IM
4646import qualified Data.Vector as V
4747import qualified Data.Vector.Unboxed as Unboxed
4848
49+-- | Map-like data structure that keeps types as keys.
4950data TypeRepMap (f :: k -> Type) = TypeRepMap
5051 { fingerprintAs :: Unboxed.Vector Word64
5152 , fingerprintBs :: Unboxed.Vector Word64
5253 , anys :: V.Vector Any
5354 }
5455
56+-- | Shows only 'Fingerprint's.
5557instance Show (TypeRepMap f) where
5658 show = show . toFps
5759
60+-- | Returnes the list of 'Fingerprint's from 'TypeRepMap'.
5861toFps :: TypeRepMap f -> [Fingerprint]
5962toFps TypeRepMap{..} = zipWith Fingerprint
6063 (Unboxed.toList fingerprintAs)
@@ -81,12 +84,15 @@ insert x = fromListPairs . addX . toPairList
8184 addX l = pairX : filter ((/= fpX) . fst) l
8285{-# INLINE insert #-}
8386
84−-- | Looks up the value at the type.
85−-- >>> let x = lookup $ insert (11 :: Int) empty
86−-- >>> x :: Maybe Int
87−-- Just 11
88−-- >>> x :: Maybe ()
89−-- Nothing
87+{- | Looks up the value at the type.
88+
89+>>> let x = lookup $ insert (Identity (11 :: Int)) empty
90+>>> x :: Maybe (Identity Int)
91+Just (Identity 11)
92+>>> x :: Maybe (Identity ())
93+Nothing
94+
95+-}
9096lookup :: forall a f . Typeable a => TypeRepMap f -> Maybe (f a)
9197lookup tVect = fromAny . (anys tVect V.!)
9298 <$> cachedBinarySearch (typeRepFingerprint $ typeRep $ Proxy @a)
@@ -97,6 +103,7 @@ lookup tVect = fromAny . (anys tVect V.!)
97103-- | Returns the size of the 'TypeRepMap'.
98104size :: TypeRepMap f -> Int
99105size = Unboxed.length . fingerprintAs
106+{-# INLINE size #-}
100107
101108-- | Binary searched based on this article
102109-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
@@ -125,12 +132,29 @@ cachedBinarySearch (Fingerprint (W64# a) (W64# b)) fpAs fpBs = inline (go 0#)
125132-- Functions for testing and benchmarking
126133----------------------------------------------------------------------------
127134
135+-- | Existential wrapper around 'Typeable' indexed by @f@ type parameter.
136+-- Useful for 'TypeRepMap' structure creation form list of 'TF's.
128137data TF f where
129138 TF :: Typeable a => f a -> TF f
130139
131140instance Show (TF f) where
132141 show (TF tf) = show $ calcFp tf
133142
143+{- | Creates 'TypeRepMap' from a list of 'TF's.
144+
145+>>> size $ fromList [TF $ Identity True, TF $ Identity 'a']
146+2
147+
148+-}
149+fromList :: forall f . [TF f] -> TypeRepMap f
150+fromList = fromListPairs . map (fp &&& an)
151+ where
152+ fp :: TF f -> Fingerprint
153+ fp (TF x) = calcFp x
154+
155+ an :: TF f -> Any
156+ an (TF x) = unsafeCoerce x
157+
134158fromF :: Typeable a => f a -> Proxy a
135159fromF _ = Proxy
136160
@@ -143,15 +167,6 @@ fromListPairs kvs = TypeRepMap (Unboxed.fromList fpAs) (Unboxed.fromList fpBs) (
143167 (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
144168 (fps, ans) = unzip $ fromSortedList $ sortWith fst $ nubPairs kvs
145169
146−fromList :: forall f . [TF f] -> TypeRepMap f
147−fromList = fromListPairs . map (fp &&& an)
148− where
149− fp :: TF f -> Fingerprint
150− fp (TF x) = calcFp x
151−
152− an :: TF f -> Any
153− an (TF x) = unsafeCoerce x
154−
155170nubPairs :: (Eq a) => [(a, b)] -> [(a, b)]
156171nubPairs = nubBy ((==) `on` fst)
157172
internal/Data/TypeRep/OptimalVector.hs+3−6
@@ -77,12 +77,9 @@ binarySearch (Fingerprint a b) fpAs fpBs =
7777 checkfpBs i =
7878 case i <# len of
7979 0# -> Nothing
80− _ ->
81− if a /= Unboxed.unsafeIndex fpAs (I# i)
82− then Nothing
83− else if b == Unboxed.unsafeIndex fpBs (I# i)
84− then Just (I# i)
85− else checkfpBs (i +# 1#)
80+ _ | a /= Unboxed.unsafeIndex fpAs (I# i) -> Nothing
81+ | b == Unboxed.unsafeIndex fpBs (I# i) -> Just (I# i)
82+ | otherwise -> checkfpBs (i +# 1#)
8683 in
8784 inline (checkfpBs (binSearchHelp (-1#) len))
8885 where
internal/Data/TypeRep/Vector.hs−1
@@ -2,7 +2,6 @@
22
33{-# LANGUAGE BangPatterns #-}
44{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE KindSignatures #-}
65{-# LANGUAGE MagicHash #-}
76{-# LANGUAGE MultiParamTypeClasses #-}
87{-# LANGUAGE PolyKinds #-}
src/Data/TypeRep/Map.hs+2
@@ -1,3 +1,5 @@
1+-- | This module introduces the 'TypeRepMap' data structure and functions to work with it.
2+
13module Data.TypeRep.Map
24 ( -- * Map type
35 TypeRepMap (..)
test/Test/TypeRep/CacheMap.hs+2−2
@@ -13,8 +13,8 @@ spec_insertLookup = do
1313 describe "Lookup Test" $ do
1414 it "returns the inserted element" $
1515 lookup (fromList [TF $ Identity 'a']) `shouldBe` Just (Identity 'a')
16− -- it "returns the second inserted value of the same type" $
17− -- lookup (fromList [TF (Identity 'b'), TF (Identity 'a')]) `shouldBe` Just (Identity 'b')
16+ it "returns the second inserted value of the same type" $
17+ lookup (fromList [TF (Identity 'b'), TF (Identity 'a')]) `shouldBe` Just (Identity 'b')
1818
1919 describe "Size Test" $ do
2020 it "is empty" $
test/Test/TypeRep/Vector.hs+1−24
@@ -10,32 +10,9 @@ import Data.TypeRep.Vector
1010
1111-- Simple test for 'lookup', 'insert' and 'size' functions.
1212spec_insertLookup :: Spec
13−spec_insertLookup = do
13+spec_insertLookup =
1414 describe "Lookup Test" $ do
1515 it "returns the inserted element" $
1616 lookup (fromList [TF (Identity 'a')]) `shouldBe` Just (Identity 'a')
1717 it "returns the second inserted value of the same type" $
1818 lookup (fromList [TF (Identity 'b'), TF (Identity 'a')]) `shouldBe` Just (Identity 'b')
19−
20−-- describe "Size Test" $ do
21−-- it "is empty" $
22−-- size empty `shouldBe` 0
23−-- it "is of size 1 when 1 element inserted" $
24−-- size (insert (Identity 'a') empty) `shouldBe` 1
25−-- it "doesn't increase size when element of the same type is added" $
26−-- size (insert (Identity 'b') $ insert (Identity 'a') empty) `shouldBe` 1
27−-- it "returns 10 when 10 different types are inserted" $
28−-- size mapOf10 `shouldBe` 10
29−--
30−--
31−-- mapOf10 :: TypeRepMap Identity
32−-- mapOf10 = insert (Identity True)
33−-- $ insert (Identity [True, False])
34−-- $ insert (Identity $ Just True)
35−-- $ insert (Identity $ Just ())
36−-- $ insert (Identity [()])
37−-- $ insert (Identity ())
38−-- $ insert (Identity "aaa")
39−-- $ insert (Identity $ Just 'a')
40−-- $ insert (Identity 'a')
41−-- $ insert (Identity (11 :: Int)) empty
test/Test/TypeRep/VectorOpt.hs+1−24
@@ -10,32 +10,9 @@ import Data.TypeRep.OptimalVector (TF (..), fromList, lookup)
1010
1111-- Simple test for 'lookup', 'insert' and 'size' functions.
1212spec_insertLookup :: Spec
13−spec_insertLookup = do
13+spec_insertLookup =
1414 describe "Lookup Test" $ do
1515 it "returns the inserted element" $
1616 lookup (fromList [TF $ Identity 'a']) `shouldBe` Just (Identity 'a')
1717 it "returns the second inserted value of the same type" $
1818 lookup (fromList [TF (Identity 'b'), TF (Identity 'a')]) `shouldBe` Just (Identity 'b')
19−
20−-- describe "Size Test" $ do
21−-- it "is empty" $
22−-- size empty `shouldBe` 0
23−-- it "is of size 1 when 1 element inserted" $
24−-- size (insert (Identity 'a') empty) `shouldBe` 1
25−-- it "doesn't increase size when element of the same type is added" $
26−-- size (insert (Identity 'b') $ insert (Identity 'a') empty) `shouldBe` 1
27−-- it "returns 10 when 10 different types are inserted" $
28−-- size mapOf10 `shouldBe` 10
29−--
30−--
31−--mapOf10 :: TypeRepMap Identity
32−--mapOf10 = insert (Identity True)
33−-- $ insert (Identity [True, False])
34−-- $ insert (Identity $ Just True)
35−-- $ insert (Identity $ Just ())
36−-- $ insert (Identity [()])
37−-- $ insert (Identity ())
38−-- $ insert (Identity "aaa")
39−-- $ insert (Identity $ Just 'a')
40−-- $ insert (Identity 'a')
41−-- $ insert (Identity (11 :: Int)) empty