packages feed

range 0.1.1.1 → 0.1.2.0

raw patch · 14 files changed

+168/−86 lines, 14 filesdep +freedep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: free

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Data.Range.Algebra: class RangeAlgebra a
+ Data.Range.Algebra: const :: a -> RangeExpr a
+ Data.Range.Algebra: data RangeExpr a
+ Data.Range.Algebra: difference :: RangeExpr a -> RangeExpr a -> RangeExpr a
+ Data.Range.Algebra: eval :: RangeAlgebra a => Algebra RangeExpr a
+ Data.Range.Algebra: instance [safe] (Ord a, Enum a) => RangeAlgebra [Range a]
+ Data.Range.Algebra: instance [safe] RangeAlgebra (a -> Bool)
+ Data.Range.Algebra: intersection :: RangeExpr a -> RangeExpr a -> RangeExpr a
+ Data.Range.Algebra: invert :: RangeExpr a -> RangeExpr a
+ Data.Range.Algebra: type Algebra f a = f a -> a
+ Data.Range.Algebra: union :: RangeExpr a -> RangeExpr a -> RangeExpr a

Files

+ Data/Range/Algebra.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE Safe #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}++module Data.Range.Algebra+  ( RangeExpr+    -- ** Operations+  , const, invert, union, intersection, difference+    -- ** Evaluation+  , Algebra, RangeAlgebra(..)+  ) where++import Prelude hiding (const)++import Data.Range.Data+import Data.Range.Algebra.Internal+import Data.Range.Algebra.Range+import Data.Range.Algebra.Predicate++import Control.Monad.Free++const :: a -> RangeExpr a+const = RangeExpr . Pure++invert :: RangeExpr a -> RangeExpr a+invert = RangeExpr . Free . Invert . getFree++union :: RangeExpr a -> RangeExpr a -> RangeExpr a+union a b = RangeExpr . Free $ Union (getFree a) (getFree b)++intersection :: RangeExpr a -> RangeExpr a -> RangeExpr a+intersection a b = RangeExpr . Free $ Intersection (getFree a) (getFree b)++difference :: RangeExpr a -> RangeExpr a -> RangeExpr a+difference a b = RangeExpr . Free $ Difference (getFree a) (getFree b)++class RangeAlgebra a where+  eval :: Algebra RangeExpr a++instance (Ord a, Enum a) => RangeAlgebra [Range a] where+  eval = iter rangeAlgebra . getFree++instance RangeAlgebra (a -> Bool) where+  eval = iter predicateAlgebra . getFree
+ Data/Range/Algebra/Internal.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE Safe #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}++module Data.Range.Algebra.Internal where++import Prelude hiding (const)++import Data.Range.Data+import Data.Range.RangeInternal++import Control.Monad.Free++data RangeExprF r+  = Invert r+  | Union r r+  | Intersection r r+  | Difference r r+  deriving (Show, Eq, Ord, Functor)++newtype RangeExpr a = RangeExpr { getFree :: Free RangeExprF a }+  deriving (Show, Eq, Ord, Functor)++type Algebra f a = f a -> a++rangeMergeAlgebra :: (Ord a, Enum a) => Algebra RangeExprF (RangeMerge a)+rangeMergeAlgebra (Invert a) = invertRM a+rangeMergeAlgebra (Union a b) = a `unionRangeMerges` b+rangeMergeAlgebra (Intersection a b) = a `intersectionRangeMerges` b+rangeMergeAlgebra (Difference a b) = a `intersectionRangeMerges` invertRM b
+ Data/Range/Algebra/Predicate.hs view
@@ -0,0 +1,9 @@+module Data.Range.Algebra.Predicate where++import Data.Range.Algebra.Internal++predicateAlgebra :: Algebra RangeExprF (a -> Bool)+predicateAlgebra (Invert f) a = not (f a)+predicateAlgebra (Union f g) a = f a || g a+predicateAlgebra (Intersection f g) a = f a && g a+predicateAlgebra (Difference f g) a = f a && not (g a)
+ Data/Range/Algebra/Range.hs view
@@ -0,0 +1,10 @@+module Data.Range.Algebra.Range where++import Data.Range.Data+import Data.Range.RangeInternal (exportRangeMerge, loadRanges)+import Data.Range.Algebra.Internal++import Control.Monad.Free++rangeAlgebra :: (Ord a, Enum a) => Algebra RangeExprF [Range a]+rangeAlgebra = exportRangeMerge . iter rangeMergeAlgebra . Free . fmap (Pure . loadRanges)
Data/Range/Data.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ -- | The Data module for common data types within the code. module Data.Range.Data where @@ -13,7 +15,7 @@    deriving(Eq, Show)  -- | These are the operations that can join two disjunct lists of ranges together.-data RangeOperation +data RangeOperation    = RangeUnion         -- ^ Represents the set union operation.    | RangeIntersection  -- ^ Represents the set intersection operation.    | RangeDifference    -- ^ Represents the set difference operation.@@ -22,7 +24,7 @@ -- you can compress an entire tree of operations on ranges into a single range quickly. -- The only purpose of this tree is to allow efficient construction of range operations -- that can be evaluated as is required.-data RangeTree a +data RangeTree a    = RangeNode RangeOperation (RangeTree a) (RangeTree a) -- ^ Combine two range trees together with a single operation    | RangeNodeInvert (RangeTree a) -- ^ Invert a range tree, this is a 'not' operation.    | RangeLeaf [Range a] -- ^ A leaf with a set of ranges that are collected together.
Data/Range/NestedRange.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ -- | Nested Ranges are common in practical usage. They appear in such forms as library -- version numbers ("Version 1.4.5.6" for example). And it is very useful to be able to -- compare these ranges to one another. This module exists for the purpose of allowing
Data/Range/Range.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ -- | This entire library is concerned with ranges and this module implements the absolute -- basic range functions. module Data.Range.Range (@@ -14,31 +16,30 @@    ) where  import Data.Range.Data-import Data.Range.RangeInternal import Data.Range.Util+import qualified Data.Range.Algebra as Alg  -- | Performs a set union between the two input ranges and returns the resultant set of -- ranges. union :: (Ord a, Enum a) => [Range a] -> [Range a] -> [Range a]-union a b = exportRangeMerge $ unionRangeMerges (loadRanges a) (loadRanges b)+union a b = Alg.eval $ Alg.union (Alg.const a) (Alg.const b) {-# INLINE union #-}  -- | Performs a set intersection between the two input ranges and returns the resultant set of -- ranges. intersection :: (Ord a, Enum a) => [Range a] -> [Range a] -> [Range a]-intersection a b = exportRangeMerge $ intersectionRangeMerges (loadRanges a) (loadRanges b)+intersection a b = Alg.eval $ Alg.intersection (Alg.const a) (Alg.const b) {-# INLINE intersection #-}  -- | Performs a set difference between the two input ranges and returns the resultant set of -- ranges. difference :: (Ord a, Enum a) => [Range a] -> [Range a] -> [Range a]-difference a b = exportRangeMerge $ intersectionRangeMerges a' (invertRM b')-  where a' = loadRanges a-        b' = loadRanges b+difference a b = Alg.eval $ Alg.difference (Alg.const a) (Alg.const b)+{-# INLINE difference #-}  -- | An inversion function, given a set of ranges it returns the inverse set of ranges. invert :: (Ord a, Enum a) => [Range a] -> [Range a]-invert = exportRangeMerge . invertRM . loadRanges+invert = Alg.eval . Alg.invert . Alg.const {-# INLINE invert #-}  -- | A check to see if two ranges overlap. If they do then true is returned; false@@ -69,7 +70,7 @@ -- | Given a list of ranges this function tells you if a value is in any of those ranges. -- This is especially useful for more complex ranges. inRanges :: (Ord a) => [Range a] -> a -> Bool-inRanges ranges value = any (flip inRange value) ranges+inRanges rs a = any (`inRange` a) rs  -- | When you create a range there may be overlaps in your ranges. However, for the sake -- of efficiency you probably want the list of ranges with no overlaps. The mergeRanges@@ -79,7 +80,7 @@ -- intersection then this is automatically done for you. Which means that a function like -- this is redundant: mergeRanges . intersection mergeRanges :: (Ord a, Enum a) => [Range a] -> [Range a]-mergeRanges = exportRangeMerge . loadRanges+mergeRanges = Alg.eval . Alg.const {-# INLINE mergeRanges #-}  -- | A set of ranges represents a collection of real values without actually instantiating@@ -89,9 +90,9 @@ -- like. fromRanges :: (Ord a, Enum a) => [Range a] -> [a] fromRanges = concatMap fromRange-   where -      fromRange range = case range of -         SingletonRange x -> [x] +   where+      fromRange range = case range of+         SingletonRange x -> [x]          SpanRange a b -> [a..b]          LowerBoundRange x -> iterate succ x          UpperBoundRange x -> iterate pred x
Data/Range/RangeInternal.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ module Data.Range.RangeInternal where  import Data.Maybe (catMaybes)
Data/Range/RangeTree.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ -- | Internally the range library converts your ranges into an internal representation of -- multiple ranges that I call a RangeMerge. When you do multiple unions and intersections -- in a row converting to and from that data structure becomes extra work that is not@@ -5,17 +7,23 @@ -- a tree of operations in advance and then evaluate them all at once. This is not only -- useful for efficiency but for parsing too. Use RangeTree's whenever you wish to perform -- multiple operations in a row and wish for it to be as efficient as possible.-module Data.Range.RangeTree +module Data.Range.RangeTree    ( evaluate    , RangeTree(..)    , RangeOperation(..)    ) where  import Data.Range.Data-import Data.Range.RangeInternal-import Data.Range.RangeTreeInternal+import qualified Data.Range.Algebra as Alg +toExpr :: RangeTree a -> Alg.RangeExpr [Range a]+toExpr (RangeLeaf a) = Alg.const a+toExpr (RangeNodeInvert a) = Alg.invert (toExpr a)+toExpr (RangeNode RangeUnion a b) = Alg.union (toExpr a) (toExpr b)+toExpr (RangeNode RangeIntersection a b) = Alg.intersection (toExpr a) (toExpr b)+toExpr (RangeNode RangeDifference a b) = Alg.difference (toExpr a) (toExpr b)+ -- | Evaluates a Range Tree into the final set of ranges that it compresses down to. Use -- this whenever you want to finally evaluate your constructed Range Tree. evaluate :: (Ord a, Enum a) => RangeTree a -> [Range a]-evaluate = exportRangeMerge . evaluateRangeTree +evaluate = Alg.eval . toExpr
− Data/Range/RangeTreeInternal.hs
@@ -1,15 +0,0 @@-module Data.Range.RangeTreeInternal where--import Data.Range.Data-import Data.Range.RangeInternal--evaluateRangeTree :: (Ord a, Enum a) => RangeTree a -> RangeMerge a-evaluateRangeTree (RangeNode operation left right) = case operation of-   RangeUnion -> leftEval `unionRangeMerges` rightEval-   RangeIntersection -> leftEval `intersectionRangeMerges` rightEval-   RangeDifference -> leftEval `intersectionRangeMerges` (invertRM rightEval)-   where-      leftEval = evaluateRangeTree left -      rightEval = evaluateRangeTree right-evaluateRangeTree (RangeNodeInvert node) = invertRM . evaluateRangeTree $ node-evaluateRangeTree (RangeLeaf ranges) = loadRanges ranges
Data/Range/Spans.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ -- This module contains every function that purely performs operations on spans. module Data.Range.Spans where 
Data/Range/Util.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE Safe #-}+ module Data.Range.Util where  -- This module is supposed to contain all of the functions that are required by the rest
Test/Range.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- This is only okay in test classes @@ -7,10 +8,12 @@ import Test.QuickCheck import Test.Framework.Providers.QuickCheck2 +import Control.Applicative ((<$>), (<*>)) import Control.Monad (liftM) import System.Random  import Data.Range.Range+import qualified Data.Range.Algebra as Alg  import Test.RangeMerge @@ -34,7 +37,7 @@  instance (Num a, Integral a, Ord a, Random a) => Arbitrary (SpanContains a) where    arbitrary = do-      begin <- arbitrarySizedIntegral +      begin <- arbitrarySizedIntegral       end <- arbitrarySizedIntegral `suchThat` (>= begin)       middle <- choose (begin, end)       return $ SpanContains (begin, end) middle@@ -53,7 +56,7 @@    ]  instance (Num a, Integral a, Ord a, Enum a) => Arbitrary (Range a) where-   arbitrary = oneof +   arbitrary = oneof       [ generateSingleton       , generateSpan       , generateLowerBound@@ -63,7 +66,7 @@       where          generateSingleton = liftM SingletonRange arbitrarySizedIntegral          generateSpan = do-            first <- arbitrarySizedIntegral +            first <- arbitrarySizedIntegral             second <- arbitrarySizedIntegral `suchThat` (> first)             return $ SpanRange first second          generateLowerBound = liftM LowerBoundRange arbitrarySizedIntegral@@ -79,59 +82,37 @@ -- ((1, 3) intersection (3, 4)) union (3, 4) => (3, 4)  prop_in_range_out_of_range_after_invert :: (Integer, [Range Integer]) -> Bool-prop_in_range_out_of_range_after_invert (point, ranges) = +prop_in_range_out_of_range_after_invert (point, ranges) =    (inRanges ranges point) /= (inRanges (invert ranges) point)  test_ranges_invert = testGroup "invert function for ranges"    [ testProperty "element in range is now out of range after invert" prop_in_range_out_of_range_after_invert    ] -prop_elements_before_union_or_true :: ([Integer], [Range Integer], [Range Integer]) -> Bool-prop_elements_before_union_or_true (points, a, b) = actual == expected-   where-      before_a = map (inRanges a) points-      before_b = map (inRanges b) points-      unionRanges = a `union` b-      actual = map (inRanges unionRanges) points-      expected = zipWith (||) before_a before_b--prop_elements_before_intersection_and_true :: ([Integer], [Range Integer], [Range Integer]) -> Bool-prop_elements_before_intersection_and_true (points, a, b) = actual == expected-   where-      before_a = map (inRanges a) points-      before_b = map (inRanges b) points-      intersectedRanges = a `intersection` b-      actual = map (inRanges intersectedRanges) points-      expected = zipWith (&&) before_a before_b--prop_elements_before_difference_and_not_true :: ([Integer], [Range Integer], [Range Integer]) -> Bool-prop_elements_before_difference_and_not_true (points, a, b) = actual == expected-   where-      before_a = map (inRanges a) points-      before_b = map (inRanges b) points-      diffedRanges = a `difference` b-      actual = map (inRanges diffedRanges) points-      expected = zipWith (&&) before_a $ map not before_b--test_union = testGroup "union function properties"-   [ testProperty "Unions from before OR together and continue to work" prop_elements_before_union_or_true-   ]+instance (Num a, Integral a, Ord a, Enum a) => Arbitrary (Alg.RangeExpr [Range a]) where+  arbitrary = frequency+    [ (3, Alg.const <$> arbitrary)+    , (1, Alg.invert <$> arbitrary)+    , (1, Alg.union <$> arbitrary <*> arbitrary)+    , (1, Alg.intersection <$> arbitrary <*> arbitrary)+    , (1, Alg.difference <$> arbitrary <*> arbitrary)+    ] -test_intersection = testGroup "intersection function properties"-   [ testProperty "Intersection before AND's to after" prop_elements_before_intersection_and_true-   ]+prop_equivalence_eval_and_evalPredicate :: ([Integer], Alg.RangeExpr [Range Integer]) -> Bool+prop_equivalence_eval_and_evalPredicate (points, expr) = actual == expected+  where+      actual = map (inRanges $ Alg.eval expr) points+      expected = map (Alg.eval $ fmap inRanges expr) points -test_difference = testGroup "difference function properties"-   [ testProperty "Difference before AND/NOT's to after" prop_elements_before_difference_and_not_true+test_algebra_equivalence = testGroup "algebra equivalence"+   [ testProperty "eval and evalPredicate" prop_equivalence_eval_and_evalPredicate    ]  --tests :: [Test]-tests = -   [ tests_inRange +tests =+   [ tests_inRange    , test_ranges_invert-   , test_union-   , test_intersection-   , test_difference+   , test_algebra_equivalence    ]    ++ rangeMergeTestCases 
range.cabal view
@@ -4,13 +4,13 @@ -- The name of the package. name:                range --- The package version.  See the Haskell package versioning policy (PVP) +-- The package version.  See the Haskell package versioning policy (PVP) -- for standards guiding when and how versions should be incremented. -- http://www.haskell.org/haskellwiki/Package_versioning_policy -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.1.1.1+version:             0.1.2.0  -- A short (one-line) description of the package. synopsis:            This has a bunch of code for specifying and managing ranges in your code.@@ -33,12 +33,12 @@ -- The package author(s). author:              Robert Massaioli --- An email address to which users can send suggestions, bug reports, and +-- An email address to which users can send suggestions, bug reports, and -- patches. maintainer:          robertmassaioli@gmail.com  -- A copyright notice.--- copyright:           +-- copyright:  category:            Data @@ -54,22 +54,26 @@                       , Data.Range.NestedRange                       , Data.Range.RangeTree                       , Data.Range.Parser-  +                      , Data.Range.Algebra+   -- Modules included in this library but not exported.   other-modules:  Data.Range.Data                   , Data.Range.RangeInternal-                  , Data.Range.RangeTreeInternal                   , Data.Range.Spans                   , Data.Range.Util+                  , Data.Range.Algebra.Internal+                  , Data.Range.Algebra.Range+                  , Data.Range.Algebra.Predicate -  +   -- Other library packages from which modules are imported.   build-depends:  base >= 4.5 && < 5                   , parsec >= 3+                  , free >=4.12    ghc-options: -Wall-   -  ++ Test-Suite test-range    type:       exitcode-stdio-1.0    main-is: Test/Range.hs@@ -80,5 +84,6 @@                   , test-framework-quickcheck2  >= 0.2 && < 0.4                   , test-framework              >= 0.4 && < 0.9                   , random                      >= 1.0+                  , free                        >= 4.12                   , range    ghc-options: -rtsopts -Wall -fno-enable-rewrite-rules