module Data.List.NonEmpty(
NonEmpty,
neHead,
neTail,
fromNonEmpty,
nonEmpty,
(|:),
toNonEmpty,
unsafeToNonEmpty,
(.:),
(.++),
reverse,
scanl,
scanl1,
scanr,
scanr1,
iterate,
cycle,
inits,
tails,
sort,
insert,
unzip,
prop_neHead,
prop_neTail,
prop_nonEmpty,
prop_nonEmptyAlias,
prop_toNonEmpty,
prop_unsafeNonEmpty,
prop_cons,
prop_append,
prop_reverse
) where
import Control.Applicative
import Control.Monad
import Control.Arrow
import Data.Foldable
import Data.Maybe
import Data.Traversable
import Data.Typeable (Typeable)
import Data.Data (Data)
import qualified Data.List as L
import Prelude hiding (foldr, reverse, scanl, scanl1, scanr, scanr1, iterate, repeat, cycle, zip, unzip)
import Test.QuickCheck hiding (NonEmpty)
data NonEmpty a = NonEmpty {
neHead :: a,
neTail :: [a]
} deriving (Eq, Ord, Typeable, Data)
instance Functor NonEmpty where
fmap f (NonEmpty h t) = NonEmpty (f h) (fmap f t)
instance Applicative NonEmpty where
pure = return
(<*>) = ap
instance Monad NonEmpty where
return = flip NonEmpty []
NonEmpty h t >>= f = let NonEmpty a b = f h
k = t >>= fromNonEmpty . f
in NonEmpty a (b ++ k)
instance Foldable NonEmpty where
foldr f x (NonEmpty h t) = foldr f x (h:t)
foldl f x (NonEmpty h t) = foldl' f x (h:t)
instance Traversable NonEmpty where
traverse f a = NonEmpty <$> head <*> tail <$> traverse f (fromNonEmpty a)
instance (Show a) => Show (NonEmpty a) where
show (NonEmpty h t) = '|' : show (h:t) ++ "|"
fromNonEmpty :: NonEmpty a -> [a]
fromNonEmpty (NonEmpty x y) = x : y
nonEmpty :: a
-> [a]
-> NonEmpty a
nonEmpty = NonEmpty
(|:) :: a
-> [a]
-> NonEmpty a
(|:) = nonEmpty
toNonEmpty :: [a]
-> Maybe (NonEmpty a)
toNonEmpty [] = Nothing
toNonEmpty (h:t) = Just (NonEmpty h t)
unsafeToNonEmpty :: [a]
-> NonEmpty a
unsafeToNonEmpty = fromMaybe (error "unsafeToNonEmpty on empty list") . toNonEmpty
(.:) :: a
-> NonEmpty a
-> NonEmpty a
a .: NonEmpty h t = NonEmpty a (h:t)
(.++) :: NonEmpty a
-> NonEmpty a
-> NonEmpty a
NonEmpty a b .++ NonEmpty c d = NonEmpty a (b ++ c:d)
reverse :: NonEmpty a
-> NonEmpty a
reverse = list L.reverse
scanl :: (b -> a -> b)
-> b
-> NonEmpty a
-> NonEmpty b
scanl = (list .) . L.scanl
scanl1 :: (a -> a -> a)
-> NonEmpty a
-> NonEmpty a
scanl1 = list . L.scanl1
scanr :: (a -> b -> b)
-> b
-> NonEmpty a
-> NonEmpty b
scanr = (list .) . L.scanr
scanr1 :: (a -> a -> a)
-> NonEmpty a
-> NonEmpty a
scanr1 = list . L.scanr1
iterate :: (a -> a)
-> a
-> NonEmpty a
iterate = (unsafeToNonEmpty .) . L.iterate
cycle :: (Foldable f) =>
f a
-> NonEmpty a
cycle = list L.cycle
inits :: [a]
-> NonEmpty [a]
inits = unsafeToNonEmpty . L.inits
tails :: [a]
-> NonEmpty [a]
tails = unsafeToNonEmpty . L.tails
sort :: (Ord a) =>
NonEmpty a
-> NonEmpty a
sort = list L.sort
insert :: (Ord a) =>
a ->
NonEmpty a ->
NonEmpty a
insert a = unsafeToNonEmpty . L.insert a . fromNonEmpty
unzip :: NonEmpty (a, b) ->
(NonEmpty a, NonEmpty b)
unzip = (unsafeToNonEmpty *** unsafeToNonEmpty) . L.unzip . fromNonEmpty
instance (Arbitrary a) => Arbitrary (NonEmpty a) where
arbitrary = nonEmpty <$> arbitrary <*> arbitrary
shrink = (unsafeToNonEmpty <$>) . shrink . fromNonEmpty
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 = fromNonEmpty (a .: as) == a : fromNonEmpty as
prop_append :: NonEmpty String -> NonEmpty String -> Bool
prop_append a b = fromNonEmpty (a .++ b) == neHead a : neTail a ++ neHead b : neTail b
prop_reverse :: NonEmpty String -> Bool
prop_reverse x = (reverse . reverse) x == x
list :: (Foldable f) => ([a] -> [b]) -> f a -> NonEmpty b
list = (unsafeToNonEmpty .) . (. toList)