module Data.Containers where
import Prelude hiding ((!!), (++), elem, enumFrom, enumFromThen, enumFromTo, enumFromThenTo, all, and, any, break, concat, concatMap, cycle, drop, dropWhile, filter, foldl, foldl1, foldr, foldr1, head, init, iterate, last, length, lines, lookup, map, mapM, mapM_, maximum, minimum, notElem, null, or, product, repeat, replicate, reverse, scanl, scanl1, scanr, scanr1, sequence, sequence_, span, splitAt, sum, tail, take, takeWhile, unlines, unwords, unzip, unzip3, words, zip, zip3, zipWith, zipWith3, fmap)
import qualified Prelude
import Data.Char(isSpace)
import qualified Data.List as List
import Data.Maybe(fromMaybe)
import Data.Monoid
import Control.Monad(liftM2)
infixl 9 !!
infix 4 `elem`, `notElem`
class (Monoid c) => Container c v | c -> v where
null :: c -> Bool
singleton :: v -> c
singleton v = build ($v)
insert :: v -> c -> c
elem :: (Eq v) => v -> c -> Bool
elem = any . (==)
notElem :: (Eq v) => v -> c -> Bool
notElem v = not . elem v
delete :: (Eq v) => v -> c -> c
delete v = snd . fold delete' (False, empty)
where
delete' v' (False,c') | v' == v = (True, c')
delete' v' (flag, c') = (flag, v' `insert` c')
deleteAll :: (Eq v) => v -> c -> c
deleteAll v = filter (/=v)
filter :: (v -> Bool) -> c -> c
filter p c = build (\ ins nil ->
fold (\ v c' -> if p v then v `ins` c' else c') nil c
)
fold :: (v -> a -> a) -> a -> c -> a
fold f s c = case splitElem c of
Nothing -> s
Just (v,c') -> f v $ fold f s c'
fold1 :: (v -> v -> v) -> c -> v
fold1 f = fromMaybe err . fold f' Nothing
where
err = error "Container.fold1: empty container"
f' v Nothing = Just v
f' v (Just v') = Just $ f v v'
genericSize :: (Num n) => c -> n
genericSize = fold (const (($!) (+1))) 0
size :: c -> Int
size = genericSize
partition :: (v -> Bool) -> c -> (c,c)
partition p = fold select (empty, empty)
where
select v ~(ts,fs) | p v = (v `insert` ts, fs)
| otherwise = (ts, v `insert` fs)
all :: (v -> Bool) -> c -> Bool
all p = fold ((&&) . p) True
and :: (v ~ Bool) => c -> Bool
and = fold (&&) True
any :: (v -> Bool) -> c -> Bool
any p = fold ((||) . p) True
or :: (v ~ Bool) => c -> Bool
or = fold (||) False
product :: (Num v) => c -> v
product = fold (*) 1
sum :: (Num v) => c -> v
sum = fold (+) 0
rigidMap :: (v -> v) -> c -> c
rigidMap f c = build (\ins nil -> fold (ins . f) nil c)
splitElem :: c -> Maybe (v, c)
splitElem = fold getFirst Nothing
where
getFirst v Nothing = Just (v, empty)
getFirst v (Just (v', c')) = Just (v', v `insert` c')
maximum :: (Ord v) => c -> v
maximum c
| null c = error "Container.maximum: empty container"
| otherwise = fold1 max c
minimum :: (Ord v) => c -> v
minimum c
| null c = error "Container.minimum: empty container"
| otherwise = fold1 min c
build :: (Container c v) => ((v -> c -> c) -> c -> c) -> c
build f = f insert empty
empty :: (Container c v) => c
empty = mempty
(++) :: (Container c v) => c -> c -> c
(++) = mappend
concat :: (Container o i, Container i v) => o -> i
concat = fold (++) empty
concatMap :: (Container f fv, Container t tv) => (fv -> t) -> f -> t
concatMap f c = build (\ ins nil -> fold ((++) . f) nil c)
convertContainer :: (Container f v, Container t v) => f -> t
convertContainer = convertContainerBy id
convertContainerBy :: (Container f fv, Container t tv)
=> (fv -> tv) -> f -> t
convertContainerBy f c = build (\ ins nil -> fold (ins . f) nil c)
class (Container (c a) a) => CFunctor c a where
map :: (CFunctor c b) => (a -> b) -> c a -> c b
map = convertContainerBy
sequence :: (Monad m, CFunctor c a, CFunctor c (m a)) => c (m a) -> m (c a)
sequence = mapM id
sequence_ :: (Monad m, Container c (m a)) => c -> m ()
sequence_ = fold (>>) (return ())
mapM :: (Monad m, CFunctor c a, CFunctor c b) => (a -> m b) -> c a -> m (c b)
mapM f = fold (liftM2 insert . f) (return empty)
mapM_ :: (Monad m, CFunctor c a) => (a -> m b) -> c a -> m ()
mapM_ f = fold ((>>) . f) (return ())
class (Container c v) => Sequence c v where
snoc :: c -> v -> c
snoc c v = c ++ singleton v
foldl :: (b -> v -> b) -> b -> c -> b
foldl f s c = case viewL c of
Nothing -> s
Just (v,c') -> let s' = f s v
in s' `seq` foldl f s' c'
foldl1 :: (v -> v -> v) -> c -> v
foldl1 f = fromMaybe err . foldl f' Nothing
where
err = error "Sequence.foldl1: empty sequence"
f' Nothing v = Just v
f' (Just v') v = Just $ f v' v
viewR :: c -> Maybe (v, c)
viewR = foldl getLast Nothing
where
getLast Nothing v = Just (v, empty)
getLast (Just (v', c')) v = Just (v', c' `snoc` v)
head :: (Sequence c v) => c -> v
head = maybe err fst . viewL
where
err = error "Sequence.head: empty sequence"
tail :: (Sequence c v) => c -> c
tail = maybe err snd . viewL
where
err = error "Sequence.tail: empty sequence"
last :: (Sequence c v) => c -> v
last = maybe err fst . viewR
where
err = error "Sequence.last: empty sequence"
init :: (Sequence c v) => c -> c
init = maybe err snd . viewR
where
err = error "Sequence.init: empty sequence"
genericTake :: (Integral n) => n -> c -> c
genericTake l = go l . viewL
where
go n _ | n <= 0 = empty
go _ Nothing = empty
go n (Just(v,c')) = v `cons` go (n1) (viewL c')
take :: Int -> c -> c
take = genericTake
takeWhile :: (v -> Bool) -> c -> c
takeWhile p = go . viewL
where
go Nothing = empty
go (Just(v,c))
| p v = v `cons` go (viewL c)
| otherwise = empty
dropWhile :: (v -> Bool) -> c -> c
dropWhile p c = build (go (viewL c))
where
go Nothing _ nil = nil
go (Just(v,c)) ins nil
| p v = go (viewL c) ins nil
| otherwise = v `ins` c
genericDrop :: (Integral n) => n -> c -> c
genericDrop l c = build (go l (viewL c))
where
go _ Nothing _ nil = nil
go n (Just(_,c)) ins nil
| n <= 0 = nil
| otherwise = go (n1) (viewL c) ins nil
drop :: Int -> c -> c
drop = genericDrop
reverse :: c -> c
reverse c = build (\ ins nil -> foldl (flip ins) nil c)
span :: (v -> Bool) -> c -> (c,c)
span p = go . viewL
where
go Nothing = (empty, empty)
go (Just(v,c))
| p v = let (t,f) = go (viewL c) in (v `cons` t, f)
| otherwise = (empty, v `cons` c)
break :: (v -> Bool) -> c -> (c,c)
break = span . (not .)
genericSplitAt :: (Integral n) => n -> c -> (c,c)
genericSplitAt n c = (genericTake n c, genericDrop n c)
splitAt :: Int -> c -> (c,c)
splitAt n c = (take n c, drop n c)
genericReplicate :: (Integral n) => n -> v -> c
genericReplicate l v = build (go l)
where
go n _ nil | n <= 0 = nil
go n ins nil = v `ins` go (n1) ins nil
replicate :: Int -> v -> c
replicate = genericReplicate
lines :: (v ~ String) => String -> c
lines = build . go
where
go "" _ nil = nil
go s ins nil = let (l, s') = Prelude.break (== '\n') s
in l `ins` case s' of
"" -> nil
(_:s'') -> go s'' ins nil
unlines :: (v ~ String) => c -> String
unlines = go . viewL
where
go Nothing = ""
go (Just(l,ls)) = l Prelude.++ '\n' : go (viewL ls)
words :: (v ~ String) => String -> c
words = build . go
where
go s ins nil = case Prelude.dropWhile isSpace s of
"" -> nil
s' -> let (w,s'') = Prelude.break isSpace s'
in w `ins` go s'' ins nil
unwords :: (v ~ String) => c -> String
unwords = go . viewL
where
go Nothing = ""
go (Just(fw,ws)) = go' fw $ viewL ws
where
go' w Nothing = w
go' w (Just(w',ws')) = w Prelude.++ ' ' : go' w' (viewL ws')
buildL :: (Sequence c v) => ((c -> v -> c) -> c -> c) -> c
buildL f = f snoc empty
cons :: (Sequence c v) => v -> c -> c
cons = insert
genericLength :: (Sequence c v, Integral n) => c -> n
genericLength = genericSize
length :: (Sequence c v) => c -> Int
length = size
foldr :: (Sequence c v) => (v -> a -> a) -> a -> c -> a
foldr = fold
foldr1 :: (Sequence c v) => (v -> v -> v) -> c -> v
foldr1 = fold1
viewL :: (Sequence c v) => c -> Maybe (v,c)
viewL = splitElem
(!!) :: (Sequence c v) => c -> Int -> v
_ !! n | n < 0 = error "Sequence.(!!): negative index"
c !! n = maybe err fst . viewL $ drop (n1) c
where
err = error "Sequence.(!!): index too large"
class (Sequence (c a) a, CFunctor c a) => SFunctor c a where
scanl :: (SFunctor c b) => (b -> a -> b) -> b -> c a -> c b
scanl f b = build . go b
where
go v c ins nil = v `ins`
case viewL c of
Nothing -> nil
Just (v',c') -> go (f v v') c ins nil
scanl1 :: (a -> a -> a) -> c a -> c a
scanl1 f = maybe (build (const id)) (uncurry (scanl f)) . viewL
scanr :: (SFunctor c b) => (a -> b -> b) -> b -> c a -> c b
scanr f b = build . go . viewL
where
go Nothing _ _ = singleton b
go (Just(v,c)) ins nil = f v (head c') `ins` c'
where
c' = go (viewL c) ins nil
scanr1 :: (a -> a -> a) -> c a -> c a
scanr1 f = maybe (build (const id)) (uncurry (scanr f)) . viewL
zipWith :: (SFunctor c b, SFunctor c d)
=> (a -> b -> d) -> c a -> c b -> c d
zipWith f ca cb = build $ wrap ca cb
where
wrap ca' cb' = go (viewL ca') (viewL cb')
go (Just(a,ca')) (Just(b,cb')) ins nil = f a b `ins` wrap ca' cb' ins nil
go _ _ _ nil = nil
zip :: (SFunctor c b, SFunctor c (a,b)) => c a -> c b -> c (a,b)
zip = zipWith (,)
unzip :: (SFunctor c b, SFunctor c (a,b)) => c (a,b) -> (c a, c b)
unzip = fold f (empty,empty)
where
f (a,b) ~(ca,cb) = (a `cons` ca, b `cons` cb)
zipWith3 :: (SFunctor c b, SFunctor c d, SFunctor c e)
=> (a -> b -> d -> e) -> c a -> c b -> c d -> c e
zipWith3 f ca cb cd = build $ wrap ca cb cd
where
wrap ca' cb' cd' = go (viewL ca') (viewL cb') (viewL cd')
go (Just(a,ca')) (Just(b,cb')) (Just(d,cd')) ins nil = f a b d
`ins`
wrap ca' cb' cd' ins nil
go _ _ _ _ nil = nil
zip3 :: (SFunctor c b, SFunctor c d, SFunctor c (a,b,d))
=> c a -> c b -> c d -> c (a,b,d)
zip3 = zipWith3 (,,)
unzip3 :: (SFunctor c b, SFunctor c d, SFunctor c (a,b,d))
=> c (a,b,d) -> (c a, c b, c d)
unzip3 = fold f (empty,empty,empty)
where
f (a,b,d) ~(ca,cb,cd) = (a `cons` ca, b `cons` cb, d `cons` cd)
class (Sequence c v) => Stream c v where
repeat :: v -> c
repeat v = v `cons` repeat v
cycle :: c -> c
cycle = checkNull
where
checkNull c
| null c = error "Stream.cycle: empty stream"
| otherwise = go c
go c = c ++ go c
iterate :: (v -> v) -> v -> c
iterate f = build . go
where
go x ins nil = x `ins` go (f x) ins nil
enumFrom :: (Enum a, Stream c a) => a -> c
enumFrom = convertContainer . Prelude.enumFrom
enumFromThen :: (Enum a, Stream c a) => a -> a -> c
enumFromThen f th = convertContainer $ Prelude.enumFromThen f th
enumFromThenTo :: (Enum a, Sequence c a) => a -> a -> a -> c
enumFromThenTo f th t = convertContainer $ Prelude.enumFromThenTo f th t
enumFromTo :: (Enum a, Sequence c a) => a -> a -> c
enumFromTo f t = convertContainer $ Prelude.enumFromTo f t
instance Container [a] a where
null = Prelude.null
insert = (:)
elem = Prelude.elem
notElem = Prelude.notElem
delete = List.delete
filter = Prelude.filter
fold = Prelude.foldr
fold1 = Prelude.foldr1
genericSize = List.genericLength
size = Prelude.length
partition = List.partition
all = Prelude.all
and = Prelude.and
any = Prelude.any
or = Prelude.or
product = Prelude.product
sum = Prelude.sum
rigidMap = map
splitElem [] = Nothing
splitElem (a:as) = Just (a,as)
maximum = Prelude.maximum
minimum = Prelude.minimum
instance CFunctor [] a where
map = Prelude.map
instance Sequence [a] a where
foldl = List.foldl'
foldl1 = List.foldl1'
viewR [] = Nothing
viewR as = Just (last as, init as)
head = Prelude.head
tail = Prelude.tail
last = Prelude.last
init = Prelude.init
genericTake = List.genericTake
take = Prelude.take
takeWhile = Prelude.takeWhile
dropWhile = Prelude.dropWhile
genericDrop = List.genericDrop
drop = Prelude.drop
reverse = Prelude.reverse
span = Prelude.span
break = Prelude.break
genericSplitAt = List.genericSplitAt
splitAt = Prelude.splitAt
genericReplicate = List.genericReplicate
replicate = Prelude.replicate
lines = Prelude.lines
unlines = Prelude.unlines
words = Prelude.words
unwords = Prelude.unwords
instance SFunctor [] a where
scanl = Prelude.scanl
scanl1 = Prelude.scanl1
scanr = Prelude.scanr
scanr1 = Prelude.scanr1
zip = Prelude.zip
zipWith = Prelude.zipWith
unzip = Prelude.unzip
zip3 = Prelude.zip3
zipWith3 = Prelude.zipWith3
unzip3 = Prelude.unzip3