TernaryTrees 0.1.2.0 → 0.1.3.0
raw patch · 8 files changed
+191/−113 lines, 8 files
Files
- Data/Map/TernaryMap.hs +99/−45
- Data/Map/TernaryMap/Internal.hs +8/−0
- Data/Set/StringSet.hs +18/−16
- Data/Set/StringSet/Internal.hs +21/−0
- Data/Set/TernarySet.hs +17/−45
- Data/Set/TernarySet/Internal.hs +14/−0
- Main.hs +6/−2
- TernaryTrees.cabal +8/−5
Data/Map/TernaryMap.hs view
@@ -4,44 +4,72 @@ singleton, member, size,- + fromList,+ lookup,+ (!),+ findWithDefault,+ insertWith,+ insertWithKey,+ keys,+ assocs,+ elems,+ null ) where+import Data.Map.TernaryMap.Internal import Data.Bits import Data.Binary import Control.Monad-import Prelude hiding (lookup)+import Control.Arrow (first)+import Prelude hiding (null,lookup) --- | TernaryMap a b is ternary tree. It is commonly used for storing word lists--- like dictionaries.-data TernaryMap a b = Node !a !(TernaryMap a b) !(TernaryMap a b) !(TernaryMap a b)- | Null b !(TernaryMap a b)- | End- deriving (Show, Eq) -- | Quickly build a tree without an initial tree. This should be used -- to create an initial tree, using insert there after.-singleton :: Ord a => [a] -> b -> TernaryMap a b-singleton (x:xs) b = Node x End (singleton xs b) End-singleton [] b = Null b End+singleton :: Ord k => [k] -> v -> TernaryMap k v+singleton (x:xs) v = Node x End (singleton xs v) End+singleton [] v = Null v End -- | Inserts an entrie into a tree. Values with the same key will be replaced -- with the newer value.-insert :: Ord a => [a] -> b -> TernaryMap a b -> TernaryMap a b-insert xss@(_:_) b End = singleton xss b-insert xss@(_:_) b (Null b' rest) = Null b' $ insert xss b rest-insert [] b End = Null b End-insert [] b (Node ele l e h) = Node ele (insert [] b l) e h-insert [] b (Null _ rest) = Null b rest-insert xss@(x:xs) b (Node ele l e h) =+insert :: Ord k => [k] -> v -> TernaryMap k v -> TernaryMap k v+insert xss@(_:_) v End = singleton xss v+insert xss@(_:_) v (Null v' rest) = Null v' $ insert xss v rest+insert [] v End = Null v End+insert [] v (Node ele l e h) = Node ele (insert [] v l) e h+insert [] v (Null _ rest) = Null v rest+insert xss@(x:xs) v (Node ele l e h) = case compare x ele of- LT -> Node ele (insert xss b l) e h- EQ -> Node ele l (insert xs b e) h- GT -> Node ele l e (insert xss b h)+ LT -> Node ele (insert xss v l) e h+ EQ -> Node ele l (insert xs v e) h+ GT -> Node ele l e (insert xss v h) --- | Returns true if the `[a]` is a key in the TernaryMap.-member :: Ord a => [a] -> TernaryMap a b -> Bool+-- | Inserts a new value into the tree with a given function that combines the new value+-- and the old value together to for a new entry.+-- +-- > insertWith f key newval (fromList [(notkey,val1),(key,oldval)]) == fromList [(notkey,val1),(key,f newval oldval)]+insertWith :: Ord k => (v -> v -> v) -> [k] -> v -> TernaryMap k v -> TernaryMap k v+insertWith _ xss@(_:_) v End = singleton xss v+insertWith f xss@(_:_) v (Null v' rest) = Null (f v v') $ insertWith f xss v rest+insertWith _ [] v End = Null v End+insertWith f [] v (Node ele l e h) = Node ele (insertWith f [] v l) e h+insertWith _ [] v (Null _ rest) = Null v rest+insertWith f xss@(x:xs) v (Node ele l e h) =+ case compare x ele of+ LT -> Node ele (insertWith f xss v l) e h+ EQ -> Node ele l (insertWith f xs v e) h+ GT -> Node ele l e (insertWith f xss v h)+++-- | Inserts a new value into the tree with a given function that combines the new value+-- and the old value together to for a new entry.+-- +-- > insertWithKey f key newval (fromList [(notkey,val1),(key,oldval)]) == fromList [(notkey,val1),(key,f key newval oldval)]+insertWithKey :: Ord k => ([k] -> v -> v -> v) -> [k] -> v -> TernaryMap k v -> TernaryMap k v+insertWithKey f ks v m = insertWith (f ks) ks v m+-- | Returns true if the `[k]` is a key in the TernaryMap.+member :: Ord k => [k] -> TernaryMap k v -> Bool member _ End = False member [] (Null _ _) = True member [] (Node _ l _ _) = member [] l@@ -53,9 +81,9 @@ GT -> member xss h -lookup :: Ord a => [a] -> TernaryMap a b -> Maybe b+lookup :: Ord k => [k] -> TernaryMap k v -> Maybe v lookup _ End = Nothing-lookup [] (Null b _) = Just b+lookup [] (Null v _) = Just v lookup [] (Node _ l _ _) = lookup [] l lookup xs (Null _ rest) = lookup xs rest lookup xss@(x:xs) (Node ele l e h) =@@ -64,54 +92,78 @@ EQ -> lookup xs e GT -> lookup xss h -(!) :: Ord a => TernaryMap a b -> [a] -> Maybe b+(!) :: Ord k => TernaryMap k v -> [k] -> Maybe v (!) = flip lookup +findWithDefault :: Ord k => v -> [k] -> TernaryMap k v -> v+findWithDefault k _ End = k+findWithDefault _ [] (Null v _) = v+findWithDefault k [] (Node _ l _ _) = findWithDefault k [] l+findWithDefault k xs (Null _ rest) = findWithDefault k xs rest+findWithDefault k xss@(x:xs) (Node ele l e h) =+ case compare x ele of+ LT -> findWithDefault k xss l+ EQ -> findWithDefault k xs e+ GT -> findWithDefault k xss h+ -- | Returns the number of non-Val Elems. not exported-treeSize :: TernaryMap a b -> Int+treeSize :: TernaryMap k v -> Int treeSize End = 0 treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h treeSize (Null _ rest) = treeSize rest -- | Counts how many entries there are in the tree.-size :: TernaryMap a b -> Int+size :: TernaryMap k v -> Int size End = 0 size (Node _ l e h) = size l + size e + size h size (Null _ rest) = 1 + size rest -- | Creates a new tree from a list of 'strings'-fromList :: Ord a => [([a],b)] -> TernaryMap a b-fromList = foldl (\tree (as,b) -> insert as b tree) empty+fromList :: Ord k => [([k],v)] -> TernaryMap k v+fromList = foldl (\tree (as,v) -> insert as v tree) empty -- | An empty map.-empty :: TernaryMap a b+empty :: TernaryMap k v empty = End -- | Makes a list of all the values in the map.-elems :: TernaryMap a b -> [b]+elems :: TernaryMap k v -> [v] elems End = [] elems (Node _ l e h) = elems l ++ (elems e ++ elems h)-elems (Null b rest) = b : elems rest+elems (Null v rest) = v : elems rest +-- | Returns a (sorted) list of all keys in the map.+keys :: TernaryMap k v -> [[k]]+keys End = []+keys (Null _ rest) = []:keys rest+keys (Node ele l e g) = keys l ++ map (ele:) (keys e) ++ keys g+++-- | Returns a (sorted) list of all keys in the map.+assocs :: TernaryMap k v -> [([k],v)]+assocs End = []+assocs (Null v rest) = ([],v):assocs rest+assocs (Node ele l e g) = assocs l ++ map (first (ele:)) (assocs e) ++ assocs g+ -- | Returns true if the map is empty.-null :: TernaryMap a b -> Bool+null :: TernaryMap k v -> Bool null End = True null _ = False --- keySet :: TernaryMap a b -> S.TernarySet a+-- keySet :: TernaryMap k v -> S.TernarySet a -- keySet End = S.End -- keySet (Node (C x) l e h) = S.Node (S.C x) (keySet l) (keySet e) (keySet h) -- keySet (Node (Val _) l e h) = S.Node (S.Null) (keySet l) (keySet e) (keySet h) -instance Functor (TernaryMap a) where+instance Functor (TernaryMap k) where fmap _ End = End- fmap f (Null b rest) = Null (f b) (fmap f rest)+ fmap f (Null v rest) = Null (f v) (fmap f rest) fmap f (Node ele l e h) = Node ele (fmap f l) (fmap f e) (fmap f h) -- | A rather long Binary instance, that uses binary numbers to indicate -- where Ends are efficiently.-instance (Binary a, Binary b) => Binary (TernaryMap a b) where+instance (Binary k, Binary v) => Binary (TernaryMap k v) where put (Node ch End End End) = do putWord8 0 put ch@@ -149,10 +201,10 @@ put l put e put h- put (Null b End) = putWord8 8 >> put b- put (Null b rest) = do+ put (Null v End) = putWord8 8 >> put v+ put (Null v rest) = do putWord8 9- put b+ put v put rest put End = putWord8 10 @@ -162,10 +214,12 @@ _ | tag < 8 -> do ch <- get- l <- if (tag `testBit` 2) then get else return End- e <- if (tag `testBit` 1) then get else return End- h <- if (tag `testBit` 0) then get else return End+ l <- if tag `testBit` 2 then get else return End+ e <- if tag `testBit` 1 then get else return End+ h <- if tag `testBit` 0 then get else return End return (Node ch l e h) 8 -> liftM (flip Null End) get 9 -> liftM2 Null get get- _ -> return End+ 10 -> return End+ _ -> error ("Invalid data in binary stream. tag: " ++ show tag) +
+ Data/Map/TernaryMap/Internal.hs view
@@ -0,0 +1,8 @@+module Data.Map.TernaryMap.Internal where++-- | TernaryMap k v is ternary tree. It is commonly used for storing word lists+-- like dictionaries.+data TernaryMap k v = Node !k !(TernaryMap k v) !(TernaryMap k v) !(TernaryMap k v)+ | Null v !(TernaryMap k v)+ | End+ deriving (Show, Eq)
Data/Set/StringSet.hs view
@@ -4,18 +4,16 @@ singleton, member, size,- fromList+ fromList,+ null,+ elems, ) where+import Data.Set.StringSet.Internal+import Prelude hiding (null) import Data.Bits import Data.Binary import Control.Monad --- | StringSet is ternary tree. It is commonly used for storing word lists--- like dictionaries for spell checking etc.-data StringSet = Node {-# UNPACK #-} !Char !StringSet !StringSet !StringSet -- | Tree node - | Null !StringSet -- | null nodes can only have a greater than branch by definition- | End -- | a branch that doesn’t contain anything- deriving (Show, Eq) -- | Inserts a new list of elements into a tree. insert :: String -> StringSet -> StringSet@@ -48,11 +46,6 @@ EQ -> member xs e GT -> member xss h --- | Returns the number of non-Null Elems-treeSize :: StringSet -> Int-treeSize End = 0-treeSize (Null rest) = treeSize rest-treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h -- | Counts how many entries there are in the tree. size :: StringSet -> Int@@ -64,6 +57,14 @@ fromList :: [String] -> StringSet fromList = foldl (flip insert) empty +-- | Returns a (sorted) list of all strings inserted into the set.+-- +-- > (elems . fromList) xs == (nub . sort) xs+elems :: StringSet -> [String]+elems End = []+elems (Null rest) = []:elems rest+elems (Node ele l e g) = elems l ++ (map (ele:) (elems e) ++ elems g)+ -- | An empty set. empty :: StringSet empty = End@@ -125,12 +126,13 @@ _ | tag < 8 -> do ch <- get- l <- if (tag `testBit` 2) then get else return End- e <- if (tag `testBit` 1) then get else return End- h <- if (tag `testBit` 0) then get else return End+ l <- if tag `testBit` 2 then get else return End+ e <- if tag `testBit` 1 then get else return End+ h <- if tag `testBit` 0 then get else return End return (Node ch l e h) 8 -> return (Null End) 9 -> liftM Null get- _ -> return End+ 10 -> return End+ _ -> error ("Invalid data in binary stream. tag: " ++ show tag)
+ Data/Set/StringSet/Internal.hs view
@@ -0,0 +1,21 @@+module Data.Set.StringSet.Internal where+import Data.Ratio++-- | StringSet is ternary tree. It is commonly used for storing word lists+-- like dictionaries for spell checking etc.+data StringSet = Node {-# UNPACK #-} !Char !StringSet !StringSet !StringSet -- | Tree node + | Null !StringSet -- | null nodes can only have a greater than branch by definition+ | End -- | a branch that doesn’t contain anything+ deriving (Show, Eq)+++-- | Returns the number of non-Null Elems+treeSize :: StringSet -> Int+treeSize End = 0+treeSize (Null rest) = treeSize rest+treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h++-- -- | A rough comparison of how much space is being used compared to+-- -- the strings as a single string+-- compRatio :: StringSet -> Ratio Int+-- compRatio s = treeSize s % length . concat . elems $ s
Data/Set/TernarySet.hs view
@@ -4,33 +4,18 @@ singleton, member, size,- fromList+ fromList,+ null,+ elems,+ ) where+import Prelude hiding (null) import Data.Bits import Data.Binary import Control.Monad+import Data.Set.TernarySet.Internal --- | Elem a is used to hold elements of a list after insertion, and--- indicate that we've reached the end of the list.--- data Elem a = C !a--- | Null--- deriving (Show, Eq)--- | TernarySet a is ternary tree. It is commonly used for storing word lists--- like dictionaries.-data TernarySet a = Node !a !(TernarySet a) !(TernarySet a) !(TernarySet a)- | Null !(TernarySet a)- | End- deriving (Show, Eq)---- | All elements are greater than the Null Elem, otherwise they are--- ordered according to their own ord instance (for the `compare (C x) (C y)` case).--- instance Ord a => Ord (Elem a) where--- compare Null Null = EQ--- compare Null x = LT--- compare x Null = GT--- compare (C x) (C y) = compare x y- -- | Quickly build a tree without an initial tree. This should be used -- to create an initial tree, using insert there after. singleton :: Ord a => [a] -> TernarySet a@@ -51,21 +36,6 @@ GT -> Node ele l e (insert xss h) --- -- General case--- insert xss@(x:xs) (Node ele l e h) =--- case compare x ele of--- LT -> Node ele (insert xss l) e h--- EQ -> Node ele l (insert xs e) h--- GT -> Node ele l e (insert xss h)--- -- Insert new elements quickly--- insert xss@(_:_) End = singleton xss--- -- End of word in non empty tree--- insert [] t@(Null rest) = t--- insert [] t@(Node ele l e h) = Node ele (insert [] l) e h--- -- End of word in empty tree--- insert [] End = Null End-- -- | Returns true if the `[a]` is in the TernarySet member :: Ord a => [a] -> TernarySet a -> Bool member _ End = False@@ -78,11 +48,6 @@ EQ -> member xs e GT -> member xss h --- | Returns the number of non-Null Elems. not exported-treeSize :: TernarySet a -> Int-treeSize End = 0-treeSize (Null rest) = treeSize rest-treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h -- | Counts how many entries there are in the tree. size :: TernarySet a -> Int@@ -94,6 +59,12 @@ fromList :: Ord a => [[a]] -> TernarySet a fromList = foldl (flip insert) empty +-- | Returns a (sorted) list of all elements inserted into the set.+elems :: TernarySet a -> [[a]]+elems End = []+elems (Null rest) = []:elems rest+elems (Node ele l e g) = elems l ++ (map (ele:) (elems e) ++ elems g)+ -- | An empty set. empty :: TernarySet a empty = End@@ -165,11 +136,12 @@ _ | tag < 8 -> do ch <- get- l <- if (tag `testBit` 2) then get else return End- e <- if (tag `testBit` 1) then get else return End- h <- if (tag `testBit` 0) then get else return End+ l <- if tag `testBit` 2 then get else return End+ e <- if tag `testBit` 1 then get else return End+ h <- if tag `testBit` 0 then get else return End return (Node ch l e h) 8 -> return (Null End) 9 -> liftM Null get- _ -> return End+ 10 -> return End+ _ -> error ("Invalid data in binary stream. tag: " ++ show tag)
+ Data/Set/TernarySet/Internal.hs view
@@ -0,0 +1,14 @@+module Data.Set.TernarySet.Internal where++-- | TernarySet a is ternary tree. It is commonly used for storing word lists+-- like dictionaries.+data TernarySet a = Node !a !(TernarySet a) !(TernarySet a) !(TernarySet a)+ | Null !(TernarySet a)+ | End+ deriving (Show, Eq)++-- | Returns the number of non-Null Elems.+treeSize :: TernarySet a -> Int+treeSize End = 0+treeSize (Null rest) = treeSize rest+treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h
Main.hs view
@@ -1,8 +1,12 @@ module Main where import Data.Binary--- import Data.Set.TernarySet-import Data.Set.StringSet+import Data.Set.TernarySet+-- These imports are here for testing mainly+-- import Data.Set.StringSet+-- import Data.Map.TernaryMap+-- import qualified Data.Set.StringSet+-- import qualified Data.Map.TernaryMap -- import Data.Set import System.IO import System.Environment
TernaryTrees.cabal view
@@ -1,5 +1,5 @@ Name: TernaryTrees-Version: 0.1.2.0+Version: 0.1.3.0 Category: Data Structures Synopsis: Efficient pure ternary tree Sets and Maps Description: Ternary trees are an efficient structure often used for storing@@ -20,11 +20,11 @@ . New in this version: .- * Changed TernaryMap to match the Set implementations more.- .- * Changed the Data.Binary instance again, hopefully it'll remain more stable from here on.+ * Moved datatype definitions into .Internal modules so that+ testing can be performed, without needing to export their definitions in the+ main modules. .- * Changed the tdict source to actually do what i said it would, by actually asking the user for input.+ * Checked a lot of the source with HLint 1.6 and made some minor changes based on that ((mostly redundant brackets)). . © 2009 by Alex Mason (<http://random.axman6.com/blog/>). BSD3 license. @@ -38,6 +38,9 @@ Data/Map/TernaryMap.hs Data/Set/TernarySet.hs Data/Set/StringSet.hs+ Data/Set/StringSet/Internal.hs+ Data/Set/TernarySet/Internal.hs+ Data/Map/TernaryMap/Internal.hs Library Build-Depends: