NonEmptyList 0.0.8 → 0.0.9
raw patch · 4 files changed
+151/−97 lines, 4 filesdep +category-extrasdep +test-frameworkdep +test-framework-hunitdep ~QuickCheckdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: category-extras, test-framework, test-framework-hunit, test-framework-quickcheck2
Dependency ranges changed: QuickCheck, base
API changes (from Hackage documentation)
- Data.List.NonEmpty: prop_append :: NonEmpty String -> NonEmpty String -> Bool
- Data.List.NonEmpty: prop_cons :: String -> NonEmpty String -> Bool
- Data.List.NonEmpty: prop_neHead :: String -> [String] -> Bool
- Data.List.NonEmpty: prop_neTail :: String -> [String] -> Bool
- Data.List.NonEmpty: prop_nonEmpty :: String -> [String] -> Bool
- Data.List.NonEmpty: prop_nonEmptyAlias :: String -> [String] -> Bool
- Data.List.NonEmpty: prop_reverse :: NonEmpty String -> Bool
- Data.List.NonEmpty: prop_toNonEmpty :: [String] -> Bool
- Data.List.NonEmpty: prop_unsafeNonEmpty :: [String] -> Property
- Data.List.NonEmpty: suml :: (Semigroup a) => NonEmpty a -> a
- Data.List.NonEmpty: sumr :: (Semigroup a) => NonEmpty a -> a
+ Data.List.NonEmpty: instance Comonad NonEmpty
+ Data.List.NonEmpty: instance Copointed NonEmpty
+ Data.List.NonEmpty: instance Pointed NonEmpty
+ Data.List.NonEmpty: instance Zip NonEmpty
+ Data.List.NonEmpty: toNonEmpty' :: NonEmpty a -> [a] -> NonEmpty a
+ Data.List.ZipNonEmpty: instance Comonad ZipNonEmpty
+ Data.List.ZipNonEmpty: instance Copointed ZipNonEmpty
+ Data.List.ZipNonEmpty: instance Pointed ZipNonEmpty
+ Data.List.ZipNonEmpty: instance Zip ZipNonEmpty
+ Test.Data.List.NonEmpty: main :: IO ()
+ Test.Data.List.NonEmpty: prop_append :: NonEmpty String -> NonEmpty String -> Bool
+ Test.Data.List.NonEmpty: prop_cons :: String -> NonEmpty String -> Bool
+ Test.Data.List.NonEmpty: prop_neHead :: String -> [String] -> Bool
+ Test.Data.List.NonEmpty: prop_neTail :: String -> [String] -> Bool
+ Test.Data.List.NonEmpty: prop_nonEmpty :: String -> [String] -> Bool
+ Test.Data.List.NonEmpty: prop_nonEmptyAlias :: String -> [String] -> Bool
+ Test.Data.List.NonEmpty: prop_reverse :: NonEmpty String -> Bool
+ Test.Data.List.NonEmpty: prop_toNonEmpty :: [String] -> Bool
+ Test.Data.List.NonEmpty: prop_unsafeNonEmpty :: [String] -> Property
+ Test.Data.List.NonEmpty: tests :: [Test]
Files
- Data/List/NonEmpty.hs +48/−67
- Data/List/ZipNonEmpty.hs +13/−18
- NonEmptyList.cabal +18/−12
- Test/Data/List/NonEmpty.hs +72/−0
Data/List/NonEmpty.hs view
@@ -10,11 +10,10 @@ nonEmpty, (|:), toNonEmpty,+ toNonEmpty', unsafeToNonEmpty, (.:), -- * List functions- suml,- sumr, reverse, scanl, scanl1,@@ -26,21 +25,14 @@ tails, sort, insert,- unzip,- -- * Tests- prop_neHead,- prop_neTail,- prop_nonEmpty,- prop_nonEmptyAlias,- prop_toNonEmpty,- prop_unsafeNonEmpty,- prop_cons,- prop_append,- prop_reverse+ unzip ) where import Control.Applicative import Control.Monad+import Control.Comonad+import Control.Functor.Pointed+import Control.Functor.Zip import Control.Arrow import Data.Foldable import Data.Maybe@@ -49,10 +41,10 @@ import Data.Data (Data) import Data.Semigroup import qualified Data.List as L-import Prelude hiding (foldr, reverse, scanl, scanl1, scanr, scanr1, iterate, repeat, cycle, zip, unzip)+import Prelude hiding (foldr, reverse, scanl, scanl1, scanr, scanr1, iterate, repeat, cycle, unzip) import Test.QuickCheck hiding (NonEmpty) --- | An list with at least one element.+-- | A list with at least one element. data NonEmpty a = NonEmpty { neHead :: a, -- ^ The head of the non-empty list. neTail :: [a] -- ^ The tail of the non-empty list.@@ -61,6 +53,12 @@ instance Functor NonEmpty where fmap f (NonEmpty h t) = NonEmpty (f h) (fmap f t) +instance Pointed NonEmpty where+ point = return++instance Copointed NonEmpty where+ extract = neHead+ instance Applicative NonEmpty where pure = return (<*>) = ap@@ -71,6 +69,10 @@ k = t >>= toList . f in NonEmpty a (b ++ k) +instance Comonad NonEmpty where+ duplicate x@(NonEmpty _ t) = NonEmpty x (case toNonEmpty t of Nothing -> []+ Just u -> toList (duplicate u))+ instance Foldable NonEmpty where foldr f x (NonEmpty h t) = f h (foldr f x t) foldl f x (NonEmpty h t) = foldl' f x (h:t)@@ -84,6 +86,13 @@ instance Semigroup (NonEmpty a) where NonEmpty a b .++. NonEmpty c d = NonEmpty a (b ++ c:d) +instance Zip NonEmpty where+ fzip = list2 zip++instance (Arbitrary a) => Arbitrary (NonEmpty a) where+ arbitrary = nonEmpty <$> arbitrary <*> arbitrary+ shrink = (unsafeToNonEmpty <$>) . shrink . toList+ -- | Constructs a non-empty list with the given head and tail. nonEmpty :: a -- ^ The head. -> [a] -- ^ The tail.@@ -102,11 +111,17 @@ toNonEmpty [] = Nothing toNonEmpty (h:t) = Just (NonEmpty h t) +-- | Converts a list to a @NonEmpty@ using the given default value for the empty list case.+toNonEmpty' :: NonEmpty a -- ^ The default return value if the given list is empty.+ -> [a] -- ^ The list to convert.+ -> NonEmpty a+toNonEmpty' d = fromMaybe d . toNonEmpty+ -- | /WARNING: Fails if given the empty list./ -- Tries to convert a list to a @NonEmpty@. unsafeToNonEmpty :: [a] -- ^ The list to convert (must not be empty). -> NonEmpty a-unsafeToNonEmpty = fromMaybe (error "unsafeToNonEmpty on empty list") . toNonEmpty+unsafeToNonEmpty = toNonEmpty' (error "unsafeToNonEmpty on empty list") -- | Prepends a value to a non-empty list. (.:) :: a -- ^ The value to prepend.@@ -114,16 +129,8 @@ -> NonEmpty a a .: NonEmpty h t = NonEmpty a (h:t) --- | Reduce left on the given non-empty list using a semigroup.-suml :: (Semigroup a) => NonEmpty a -> a-suml (NonEmpty h t) = L.foldl1' (.++.) (h:t)---- | Reduce right on the given non-empty list using a semigroup.-sumr :: (Semigroup a) => NonEmpty a -> a-sumr (NonEmpty h t) = L.foldr1 (.++.) (h:t)- -- | Reverses the elements of the (finite) non-empty list.-reverse :: NonEmpty a+reverse :: NonEmpty a -- ^ A finite non-empty list. -> NonEmpty a reverse = list L.reverse @@ -173,54 +180,28 @@ sort = list L.sort insert :: (Ord a) =>- a ->- NonEmpty a ->- NonEmpty a+ a+ -> NonEmpty a+ -> NonEmpty a insert a = unsafeToNonEmpty . L.insert a . toList -unzip :: NonEmpty (a, b) ->- (NonEmpty a, NonEmpty b)+unzip :: NonEmpty (a, b)+ -> (NonEmpty a, NonEmpty b) unzip = (unsafeToNonEmpty *** unsafeToNonEmpty) . L.unzip . toList --------------- TESTS ----------------instance (Arbitrary a) => Arbitrary (NonEmpty a) where- arbitrary = nonEmpty <$> arbitrary <*> arbitrary- shrink = (unsafeToNonEmpty <$>) . shrink . toList--prop_neHead :: String -> [String] -> Bool-prop_neHead h t = neHead (nonEmpty h t) == h--prop_neTail :: String -> [String] -> Bool-prop_neTail h t = neTail (nonEmpty h t) == t--prop_nonEmpty :: String -> [String] -> Bool-prop_nonEmpty h t = toList (nonEmpty h t) == h:t--prop_nonEmptyAlias :: String -> [String] -> Bool-prop_nonEmptyAlias h t = nonEmpty h t == h |: t--prop_toNonEmpty :: [String] -> Bool-prop_toNonEmpty x = toNonEmpty x == case x of [] -> Nothing- (h:t) -> Just (nonEmpty h t)--prop_unsafeNonEmpty :: [String] -> Property-prop_unsafeNonEmpty x = not (null x) ==> prop_toNonEmpty x--prop_cons :: String -> NonEmpty String -> Bool-prop_cons a as = toList (a .: as) == a : toList as--prop_append :: NonEmpty String -> NonEmpty String -> Bool-prop_append a b = toList (a .++. b) == neHead a : neTail a ++ neHead b : neTail b--prop_reverse :: NonEmpty String -> Bool-prop_reverse x = (reverse . reverse) x == x- ------------------ -- Not exported -- ------------------ -list :: (Foldable f) => ([a] -> [b]) -> f a -> NonEmpty b+list :: Foldable f =>+ ([a] -> [b])+ -> f a+ -> NonEmpty b list = (unsafeToNonEmpty .) . (. toList)++list2 :: Foldable f =>+ ([a] -> [b] -> [c])+ -> f a+ -> f b+ -> NonEmpty c+list2 f a b = unsafeToNonEmpty (f (toList a) (toList b))
Data/List/ZipNonEmpty.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-} -- | A wrapper of @NonEmpty@ that has a zip-like @Applicative@ instance. module Data.List.ZipNonEmpty(@@ -18,40 +18,35 @@ import Data.Data (Data) import Data.List.NonEmpty import Control.Applicative+import Control.Comonad+import Control.Functor.Pointed+import Control.Functor.Zip -- | A wrapper of @NonEmpty@ that has a zip-like @Applicative@ instance. newtype ZipNonEmpty a = Z { -- | Unwraps a zip-like non-empty list. ne :: NonEmpty a-} deriving (Eq, Ord, Typeable, Data)+} deriving (Eq, Ord, Typeable, Data, Functor, Pointed, Copointed, Zip, Comonad, Semigroup) -- | Wraps a non-empty list.-zipNe :: NonEmpty a ->- ZipNonEmpty a+zipNe :: NonEmpty a+ -> ZipNonEmpty a zipNe = Z -- | Runs a function for non-empty lists on zip-like non-empty lists.-usingNe :: (NonEmpty a ->- NonEmpty b) ->- ZipNonEmpty a ->- ZipNonEmpty b+usingNe :: (NonEmpty a -> NonEmpty b)+ -> ZipNonEmpty a+ -> ZipNonEmpty b usingNe = (zipNe .) . (. ne) -- | Runs a function for zip-like non-empty lists on non-empty lists.-usingZne :: (ZipNonEmpty a ->- ZipNonEmpty b) ->- NonEmpty a ->- NonEmpty b+usingZne :: (ZipNonEmpty a -> ZipNonEmpty b)+ -> NonEmpty a+ -> NonEmpty b usingZne = (ne .) . (. zipNe) instance (Show a) => Show (ZipNonEmpty a) where show = show . ne--instance Semigroup (ZipNonEmpty a) where- Z a .++. Z b = Z (a .++. b)--instance Functor ZipNonEmpty where- fmap = usingNe . fmap instance Applicative ZipNonEmpty where pure = zipNe . unsafeToNonEmpty . repeat
NonEmptyList.cabal view
@@ -1,5 +1,5 @@ Name: NonEmptyList-Version: 0.0.8+Version: 0.0.9 License: BSD3 License-File: LICENSE Synopsis: A list with a length of at least one.@@ -8,19 +8,25 @@ Category: Data Author: Tony Morris, Oliver Taylor, Eelis van der Weegen Maintainer: code@tmorris.net-Copyright: 2010 Tony Morris, Oliver Taylor-build-type: Simple-cabal-version: >= 1.2+Copyright: 2010 Tony Morris, Oliver Taylor, Eelis van der Weegen+Build-Type: Simple+Cabal-Version: >= 1.2+Stability: Experimental Flag small_base- Description: Choose the new, split-up base package.+ Description: Choose the new, split-up base package. Library- if flag(small_base)- Build-Depends: base < 5 && >= 3, QuickCheck >= 2, Semigroup- else- Build-Depends: base < 5 && >= 3, QuickCheck >= 2, Semigroup+ Build-Depends: base >= 3 && < 5,+ test-framework,+ test-framework-hunit,+ test-framework-quickcheck2,+ QuickCheck,+ Semigroup,+ category-extras - GHC-Options: -Wall- Exposed-Modules: Data.List.NonEmpty- Data.List.ZipNonEmpty+ GHC-Options: -Wall++ Exposed-Modules: Data.List.NonEmpty+ Data.List.ZipNonEmpty+ Test.Data.List.NonEmpty
+ Test/Data/List/NonEmpty.hs view
@@ -0,0 +1,72 @@+module Test.Data.List.NonEmpty where++import Prelude hiding (reverse)+import Data.List.NonEmpty+import Data.Foldable+import Data.Semigroup+import Test.QuickCheck hiding (NonEmpty)+import Test.Framework+import Test.Framework.Providers.QuickCheck2 (testProperty)++main :: IO ()+main = defaultMain tests++tests :: [Test]+tests =+ [+ testGroup "NonEmpty"+ [+ testProperty "neHead" prop_neHead,+ testProperty "neTail" prop_neTail,+ testProperty "nonEmpty" prop_nonEmpty,+ testProperty "nonEmptyAlias" prop_nonEmptyAlias,+ testProperty "toNonEmpty" prop_toNonEmpty,+ testProperty "unsafeNonEmpty" prop_unsafeNonEmpty,+ testProperty "cons" prop_cons,+ testProperty "append" prop_append,+ testProperty "reverse" prop_reverse+ ]+ ]++prop_neHead :: String+ -> [String]+ -> Bool+prop_neHead h t = neHead (nonEmpty h t) == h++prop_neTail :: String+ -> [String]+ -> Bool+prop_neTail h t = neTail (nonEmpty h t) == t++prop_nonEmpty :: String+ -> [String]+ -> Bool+prop_nonEmpty h t = toList (nonEmpty h t) == h:t++prop_nonEmptyAlias :: String+ -> [String]+ -> Bool+prop_nonEmptyAlias h t = nonEmpty h t == h |: t++prop_toNonEmpty :: [String]+ -> Bool+prop_toNonEmpty x = toNonEmpty x == case x of [] -> Nothing+ (h:t) -> Just (nonEmpty h t)++prop_unsafeNonEmpty :: [String]+ -> Property+prop_unsafeNonEmpty x = not (null x) ==> prop_toNonEmpty x++prop_cons :: String+ -> NonEmpty String+ -> Bool+prop_cons a as = toList (a .: as) == a : toList as++prop_append :: NonEmpty String+ -> NonEmpty String+ -> Bool+prop_append a b = toList (a .++. b) == neHead a : neTail a ++ neHead b : neTail b++prop_reverse :: NonEmpty String+ -> Bool+prop_reverse x = (reverse . reverse) x == x