packages feed

bimap 0.2.1 → 0.2.2

raw patch · 6 files changed

+358/−36 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Bimap: deleteFindMax :: (Ord b) => Bimap a b -> ((a, b), Bimap a b)
+ Data.Bimap: deleteFindMaxR :: (Ord a) => Bimap a b -> ((b, a), Bimap a b)
+ Data.Bimap: deleteFindMin :: (Ord b) => Bimap a b -> ((a, b), Bimap a b)
+ Data.Bimap: deleteFindMinR :: (Ord a) => Bimap a b -> ((b, a), Bimap a b)
+ Data.Bimap: deleteMax :: (Ord b) => Bimap a b -> Bimap a b
+ Data.Bimap: deleteMaxR :: (Ord a) => Bimap a b -> Bimap a b
+ Data.Bimap: deleteMin :: (Ord b) => Bimap a b -> Bimap a b
+ Data.Bimap: deleteMinR :: (Ord a) => Bimap a b -> Bimap a b
+ Data.Bimap: findMax :: Bimap a b -> (a, b)
+ Data.Bimap: findMaxR :: Bimap a b -> (b, a)
+ Data.Bimap: findMin :: Bimap a b -> (a, b)
+ Data.Bimap: findMinR :: Bimap a b -> (b, a)
+ Data.Bimap: fromAList :: (Ord a, Ord b) => [(a, b)] -> Bimap a b
+ Data.Bimap: tryInsert :: (Ord a, Ord b) => a -> b -> Bimap a b -> Bimap a b

Files

Data/Bimap.hs view
@@ -35,10 +35,25 @@     singleton,     -- * Update     insert,+    tryInsert,     delete,     deleteR,+    -- * Min\/Max+    findMin,+    findMinR,+    findMax,+    findMaxR,+    deleteMin,+    deleteMinR,+    deleteMax,+    deleteMaxR,+    deleteFindMin,+    deleteFindMinR,+    deleteFindMax,+    deleteFindMaxR,     -- * Conversion\/traversal     fromList,+    fromAList,     toList,     toAscList,     toAscListR,@@ -76,47 +91,39 @@     (==) bx by = toAscList bx == toAscList by  {-| /O(1)/. The empty bimap.- /Version: 0.2/-} empty :: Bimap a b empty = MkBimap M.empty M.empty  {-| /O(1)/. A bimap with a single element.- /Version: 0.2/-} singleton :: a -> b -> Bimap a b singleton x y = MkBimap (M.singleton x y) (M.singleton y x)  {-| /O(1)/. Is the bimap empty?- /Version: 0.2/-} null :: Bimap a b -> Bool null (MkBimap left _) = M.null left  {-| /O(1)/. The number of elements in the bimap.- /Version: 0.2/-} size :: Bimap a b -> Int size (MkBimap left _) = M.size left  {-| /O(log n)/. Is the specified value a member of the bimap?- /Version: 0.2/-} member :: (Ord a, Ord b) => a -> Bimap a b -> Bool member x (MkBimap left _) = M.member x left {-| /O(log n)/. A version of 'member' specialized to the right key.- /Version: 0.2/-} memberR :: (Ord a, Ord b) => b -> Bimap a b -> Bool memberR y (MkBimap _ right) = M.member y right  {-| /O(log n)/. Is the specified value not a member of the bimap?- /Version: 0.2/-} notMember :: (Ord a, Ord b) => a -> Bimap a b -> Bool notMember = not .: member {-| /O(log n)/. A version of 'notMember' specialized to the right key.- /Version: 0.2/-} notMemberR :: (Ord a, Ord b) => b -> Bimap a b -> Bool notMemberR = not .: memberR@@ -136,7 +143,6 @@ {-| /O(log n)/. Are the two values not in the bimap, or not associated with each other? (Complement of 'pairMember'.)- /Version: 0.2/-} pairNotMember :: (Ord a, Ord b)               => (a, b) -> Bimap a b -> Bool@@ -150,12 +156,22 @@  /Version: 0.2/-} insert :: (Ord a, Ord b)-        => a -> b -> Bimap a b -> Bimap a b+       => a -> b -> Bimap a b -> Bimap a b insert x y = delete x >>> deleteR y >>> unsafeInsert x y     where     (>>>) = flip (.)  {-| /O(log n)/.+Insert a pair of values into the bimap, but only if neither is+already in the bimap.+/Version: 0.2.2/-}+tryInsert :: (Ord a, Ord b)+          => a -> b -> Bimap a b -> Bimap a b+tryInsert x y bi+    | (x `notMember` bi && y `notMemberR` bi) = unsafeInsert x y bi+    | otherwise                               = bi++{-| /O(log n)/. Insert a pair of values into the bimap, without checking for overlapping bindings. @@ -190,7 +206,6 @@ delete = deleteE . Left  {-| /O(log n)/ A version of 'delete' specialized to the right key.- /Version: 0.2/-} deleteR :: (Ord a, Ord b) => b -> Bimap a b -> Bimap a b deleteR = deleteE . Right@@ -212,7 +227,6 @@ {-| /O(log n)/. A version of 'lookup' that is specialized to the right key, and returns the corresponding left key.- /Version: 0.2/-} lookupR :: (Ord a, Ord b, Monad m)         => b -> Bimap a b -> m a@@ -224,7 +238,6 @@ {-| /O(log n)/. Find the right key corresponding to a given left key. Calls @'error'@ when the key is not in the bimap.- /Version: 0.2/-} (!) :: (Ord a, Ord b) => Bimap a b -> a -> b (!) bi x = case lookup x bi of@@ -234,7 +247,6 @@ {-| /O(log n)/. A version of @(!)@ that is specialized to the right key, and returns the corresponding left key.- /Version: 0.2/-} (!>) :: (Ord a, Ord b) => Bimap a b -> b -> a (!>) bi y = case lookupR y bi of@@ -244,14 +256,28 @@ {-| /O(n*log n)/. Build a map from a list of pairs. If there are any overlapping pairs in the list, the later ones will override the earlier ones.- /Version: 0.2/-} fromList :: (Ord a, Ord b)          => [(a, b)] -> Bimap a b fromList xs = foldl' (flip . uncurry $ insert) empty xs -{-| /O(n)/. Convert to a list of associated pairs.+{-| /O(n*log n)/.+Build a map from a list of pairs. Unlike 'fromList', earlier pairs+will take precedence over later ones. +The name @fromAList@ is a reference to Lisp-style association+lists, where associations can be overridden by prepending new ones.++Note that when duplicates occur in both the keys and in the values,+@fromList xs /= fromAList (reverse xs)@. However, if either+contains no duplicates, then the equality holds.++/Version: 0.2.2/-}+fromAList :: (Ord a, Ord b)+          => [(a, b)] -> Bimap a b+fromAList xs = foldl' (flip . uncurry $ tryInsert) empty xs++{-| /O(n)/. Convert to a list of associated pairs. /Version: 0.2/-} toList :: Bimap a b -> [(a, b)] toList = toAscList@@ -281,46 +307,40 @@ {-| /O(n)/. Return all associated pairs in the bimap, with the left-hand values in ascending order.- /Version: 0.2/-} assocs :: Bimap a b -> [(a, b)] assocs = toList  {-| /O(n)/. Return all left-hand keys in the bimap in ascending order.- /Version: 0.2/-} keys :: Bimap a b -> [a] keys (MkBimap left _) = M.keys left  {-| /O(n)/. Return all right-hand keys in the bimap in ascending order.- /Version: 0.2/-} keysR :: Bimap a b -> [b] keysR (MkBimap _ right) = M.keys right  {-| /O(n)/. An alias for 'keysR'.- /Version: 0.2/-} elems :: Bimap a b -> [b] elems = keysR  {-| /O(1)/. Extract only the left-to-right component of a bimap.- /Version: 0.2.1/-} toMap :: Bimap a b -> M.Map a b toMap (MkBimap left _) = left  {-| /O(1)/. Extract only the right-to-left component of a bimap.- /Version: 0.2.1/-} toMapR :: Bimap a b -> M.Map b a toMapR (MkBimap _ right) = right  {-| /O(n*log n)/.-Test if the internal bimap structure is valid.-+Test if the internal bimap structure is valid. This should be true+for any bimap created using the public interface. /Version: 0.2/-} valid :: (Ord a, Ord b)       => Bimap a b -> Bool@@ -335,7 +355,6 @@  {-| /O(1)/. Reverse the positions of the two element types in the bimap.- /Version: 0.2/-} twist ::  Bimap a b -> Bimap b a twist (MkBimap left right) = MkBimap right left@@ -343,7 +362,6 @@ {-| /O(1)/. Reverse the positions of the two element types in a bimap transformation.- /Version: 0.2/-} twisted :: (Bimap a b -> Bimap a b) -> (Bimap b a -> Bimap b a) twisted f = twist . f . twist@@ -351,8 +369,99 @@ {-| /O(n)/. Fold the association pairs in the map, such that @'fold' f z == 'foldr' f z . 'assocs'@.- /Version: 0.2/-} fold :: (a -> b -> c -> c) -> c -> Bimap a b -> c fold f z = foldr (uncurry f) z . assocs++{-| /O(log n)/.+Delete and find the element with maximal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteFindMax :: (Ord b) => Bimap a b -> ((a, b), Bimap a b)+deleteFindMax (MkBimap left right) = ((a, b), MkBimap left' right') where+    ((a, b), left') = M.deleteFindMax left+    right' = b `M.delete` right++{-| /O(log n)/.+Delete and find the element with maximal right key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteFindMaxR :: (Ord a) => Bimap a b ->  ((b, a), Bimap a b)+deleteFindMaxR = second twist . deleteFindMax . twist where+    second f (x, y) = (x, f y)++{-| /O(log n)/.+Delete the element with maximal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteMax :: (Ord b) => Bimap a b -> Bimap a b+deleteMax = snd . deleteFindMax+ +{-| /O(log n)/.+Delete the element with maximal right key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteMaxR :: (Ord a) => Bimap a b -> Bimap a b+deleteMaxR = snd . deleteFindMaxR++{-| /O(log n)/.+Find the element with maximal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+findMax :: Bimap a b -> (a, b)+findMax = M.findMax . toMap++{-| /O(log n)/.+Find the element with maximal right key. The +right-hand key is the first entry in the pair.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+findMaxR :: Bimap a b -> (b, a)+findMaxR = M.findMax . toMapR++{-| /O(log n)/.+Delete and find the element with minimal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteFindMin :: (Ord b) => Bimap a b -> ((a, b), Bimap a b)+deleteFindMin (MkBimap left right) = ((a, b), MkBimap left' right') where+    ((a, b), left') = M.deleteFindMin left+    right' = b `M.delete` right++{-| /O(log n)/.+Delete and find the element with minimal right key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteFindMinR :: (Ord a) => Bimap a b ->  ((b, a), Bimap a b)+deleteFindMinR = second twist . deleteFindMin . twist where+    second f (x, y) = (x, f y)++{-| /O(log n)/.+Delete the element with minimal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteMin :: (Ord b) => Bimap a b -> Bimap a b+deleteMin = snd . deleteFindMin+ +{-| /O(log n)/.+Delete the element with minimal right key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+deleteMinR :: (Ord a) => Bimap a b -> Bimap a b+deleteMinR = snd . deleteFindMinR++{-| /O(log n)/.+Find the element with minimal left key.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+findMin :: Bimap a b -> (a, b)+findMin = M.findMin . toMap++{-| /O(log n)/.+Find the element with minimal right key. The +right-hand key is the first entry in the pair.+Calls @'error'@ if the bimap is empty.+/Version: 0.2.2/-}+findMinR :: Bimap a b -> (b, a)+findMinR = M.findMin . toMapR 
HISTORY view
@@ -1,3 +1,10 @@+Version 0.2.2 (18 Jun 2008)++  * added min/max functions (thanks to Jochem Berndsen)+  * added tryInsert+  * added fromAList+  * more tests for existing functionality+ Version 0.2.1 (6 Feb 2008)    * removed MTL dependency
LICENSE view
@@ -1,4 +1,4 @@-Copyright Stuart Cook 2008+Copyright Stuart Cook and contributors 2008  All rights reserved. 
Test/Tests.hs view
@@ -1,6 +1,6 @@ module Test.Tests where -import Prelude hiding (null)+import Prelude hiding (null, lookup) import Test.QuickCheck  import Data.Bimap@@ -12,10 +12,14 @@     coarbitrary = coarbitrary . toList  +-- empty bimap has zero size prop_size_empty = size empty == 0 +-- empty bimap is null prop_null_empty = null empty +-- when converting from a list and back, each pair in the latter+-- list was originally in the former list -- (heh, this is probably made redundant by polymorphism) prop_fromList_toList xs =     let xs' = toList . fromList $ xs@@ -34,10 +38,28 @@         ((>1) . length . filter (== x) . map fst $ xs) ||         ((>1) . length . filter (== y) . map snd $ xs) +-- a bimap created from a list is no larger than the list prop_fromList_size xs = (size $ fromList xs) <= length xs     where     _ = xs :: [(Int, Integer)] +-- if a pair is a member of the bimap, then both elements are present+-- and associated with each other+prop_pairMember bi k v =+    ((k, v) `pairMember` bi) == and+        [ k `member`  bi+        , v `memberR` bi+        , lookup  k bi == Just v+        , lookupR v bi == Just k+        ]+    where+    _ = bi :: Bimap Int Integer++-- an inserted pair ends up in the bimap+prop_insert_member bi k v = (k, v) `pairMember` (insert k v bi)+    where+    _ = bi :: Bimap Int Integer+ -- if we insert a pair with an existing value, the old value's twin -- is no longer in the bimap prop_clobberL bi b' =@@ -54,11 +76,26 @@     where     (a, b) = head . toList $ bi :: (Int, Integer) +-- if we politely insert two members, neither of which is present,+-- then the two are successfully associated+prop_tryInsert_member bi k v = (k, v) `neitherMember` bi ==>+    pairMember (k, v) (tryInsert k v bi)+    where+    _ = bi :: Bimap Int Integer+    neitherMember (k, v) bi = k `notMember` bi && v `notMemberR` bi++-- polite insertion will never remove existing associations+prop_tryInsert_not_clobber bi k v =+    all (flip pairMember $ tryInsert k v bi) (toList bi)+    where+    _ = bi :: Bimap Int Integer+ -- an arbitrary bimap is valid prop_valid bi = valid bi     where     _ = bi :: Bimap Int Integer +-- if x maps to y, then y maps to x prop_member_twin bi = flip all (toList bi) $ \(x, y) -> and     [ (bi !  x) `memberR` bi     , (bi !> y) `member`  bi@@ -66,6 +103,7 @@     where     _ = bi :: Bimap Int Integer +-- deleting an element removes it from the map prop_delete bi = flip all (toList bi) $ \(x, y) -> and     [ x `notMember`  delete  x bi     , y `notMemberR` deleteR y bi@@ -73,6 +111,7 @@     where     _ = bi :: Bimap Int Integer +-- deleting an element removes its twin from the map prop_delete_twin bi = flip all (toList bi) $ \(x, y) -> and     [ (bi !  x) `notMemberR` delete  x bi     , (bi !> y) `notMember`  deleteR y bi@@ -80,6 +119,8 @@     where     _ = bi :: Bimap Int Integer +-- a singleton bimap is valid, has one association, and the two+-- given values map to each other prop_singleton x y = let bi = singleton x y in and     [ valid bi     , (x, y) `pairMember` bi@@ -90,7 +131,169 @@     where     _ = (x, y) :: (Int, Integer) +-- twist is its own inverse prop_twist_twist bi =     bi == (twist . twist $ bi)     where     _ = bi :: Bimap Int Integer++-- the property (fromList == fromAList . reverse) only holds+-- if either the left or right values are all distinct+prop_fromList_fromAList xs = and+    [ fromList  ys == fromAList rys+    , fromList rys == fromAList  ys+    ]+    where+    ys = xs `zip` [1..] :: [(Int, Integer)]+    rys = reverse ys++swap (x, y) = (y, x)++prop_deleteMin_is_delete bi = not (null bi) ==>+    snd (deleteFindMin bi) `equals` deleteMin bi+    where+    _ = bi :: Bimap Int Integer+    x `equals` y = toList x == toList y++prop_deleteMin_is_find bi = not (null bi) ==>+    fst (deleteFindMin bi) == findMin bi+    where+    _ = bi :: Bimap Int Integer++prop_deleteMin_deletes bi = not (null bi) ==>+    fst (deleteFindMin bi) `pairNotMember` snd (deleteFindMin bi)+    where+    _ = bi :: Bimap Int Integer++prop_findMin_member bi = not (null bi) ==>+    findMin bi `pairMember` bi+    where+    _ = bi :: Bimap Int Integer+        +prop_singleton_is_findMin x y = findMin bi == (x, y)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_singleton_deleteMin_empty x y = null (deleteMin bi)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_findMin_is_minimal bi = all (\ (a, _) -> a >= x) lst+    where+    lst = toList bi+    _ = bi :: Bimap Int Integer+    x = fst . findMin $ bi++prop_deleteMinR_is_delete bi = not (null bi) ==>+    snd (deleteFindMinR bi) == deleteMinR bi +    where+    _ = bi :: Bimap Int Integer++prop_deleteMinR_is_find bi = not (null bi) ==>+    fst (deleteFindMinR bi) == findMinR bi +    where+    _ = bi :: Bimap Int Integer++prop_deleteMinR_deletes bi = not (null bi) ==>+    (swap . fst) (deleteFindMinR bi) `pairNotMember` snd (deleteFindMinR bi)+    where+    _ = bi :: Bimap Int Integer++prop_findMinR_member bi = not (null bi) ==>+    swap (findMinR bi) `pairMember` bi+    where+    _ = bi :: Bimap Int Integer+        +prop_singleton_is_findMinR x y = findMinR bi == (y, x)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_singleton_deleteMinR_empty x y = null (deleteMinR bi)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_findMinR_is_minimal bi = all (\ (_, b) -> b >= y) lst+    where+    lst = toList bi+    _ = bi :: Bimap Int Integer+    y = fst . findMinR $ bi++++prop_deleteMax_is_delete bi = not (null bi) ==>+    snd (deleteFindMax bi) `equals` deleteMax bi+    where+    _ = bi :: Bimap Int Integer+    x `equals` y = toList x == toList y++prop_deleteMax_is_find bi = not (null bi) ==>+    fst (deleteFindMax bi) == findMax bi+    where+    _ = bi :: Bimap Int Integer++prop_deleteMax_deletes bi = not (null bi) ==>+    fst (deleteFindMax bi) `pairNotMember` snd (deleteFindMax bi)+    where+    _ = bi :: Bimap Int Integer++prop_findMax_member bi = not (null bi) ==>+    findMax bi `pairMember` bi+    where+    _ = bi :: Bimap Int Integer+        +prop_singleton_is_findMax x y = findMax bi == (x, y)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_singleton_deleteMax_empty x y = null (deleteMax bi)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_findMax_is_maximal bi = all (\ (a, _) -> a <= x) lst+    where+    lst = toList bi+    _ = bi :: Bimap Int Integer+    x = fst . findMax $ bi++prop_deleteMaxR_is_delete bi = not (null bi) ==>+    snd (deleteFindMaxR bi) == deleteMaxR bi +    where+    _ = bi :: Bimap Int Integer++prop_deleteMaxR_is_find bi = not (null bi) ==>+    fst (deleteFindMaxR bi) == findMaxR bi+    where+    _ = bi :: Bimap Int Integer++prop_deleteMaxR_deletes bi = not (null bi) ==>+    (swap . fst) (deleteFindMaxR bi) `pairNotMember` snd (deleteFindMaxR bi)+    where+    _ = bi :: Bimap Int Integer++prop_findMaxR_member bi = not (null bi) ==>+    swap (findMaxR bi) `pairMember` bi+    where+    _ = bi :: Bimap Int Integer+        +prop_singleton_is_findMaxR x y = findMaxR bi == (y, x)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_singleton_deleteMaxR_empty x y = null (deleteMaxR bi)+    where+    bi :: Bimap Int Integer+    bi = singleton x y++prop_findMaxR_is_maximal bi = all (\ (_, b) -> b <= y) lst+    where+    lst = toList bi+    _ = bi :: Bimap Int Integer+    y = fst . findMaxR $ bi+
bimap.cabal view
@@ -1,6 +1,6 @@ cabal-version:       >= 1.2.3.0 name:                bimap-version:             0.2.1+version:             0.2.2 synopsis:            Bidirectional mapping between two key types description:   A data structure representing a bidirectional mapping between two@@ -9,7 +9,7 @@ category:            Data license:             BSD3 license-file:        LICENSE-copyright:           Stuart Cook 2008+copyright:           Stuart Cook and contributors 2008 author:              Stuart Cook maintainer:          scook0@gmail.com homepage:            http://code.haskell.org/bimap@@ -31,7 +31,7 @@     build-depends:       base >= 3, containers   else     build-depends:       base < 3-  ghc-options:         -Wall -O2+  ghc-options:         -Wall   exposed-modules:       Data.Bimap 
tests.sh view
@@ -1,5 +1,8 @@ #!/bin/bash-# ensure that an error in the test program doesn't accidentally-# produce success-set -o pipefail-(runhaskell Test/RunTests.hs | tee .test.log) && if grep Falsifiable .test.log >/dev/null; then exit 1; fi++rm .test.log 2>/dev/null+runhaskell Test/RunTests.hs > .test.log || exit 1+cat .test.log || exit 2+grep Falsifiable .test.log >/dev/null && exit 3+echo "~~ all tests passed ~~"+exit 0