module Data.CircularList (
CList,
empty, fromList, singleton,
update, reverseDirection,
leftElements, rightElements, toList, toInfList,
focus, insertL, insertR,
removeL, removeR,
allRotations, rotR, rotL, rotN, rotNR, rotNL,
rotateTo, findRotateTo,
filterR, filterL, foldrR, foldrL, foldlR, foldlL,
balance, packL, packR,
isEmpty, size,
) where
import Control.Applicative hiding (empty)
import Prelude
import Data.List(find,unfoldr,foldl')
import Control.DeepSeq(NFData(..))
import Control.Monad(join)
import qualified Data.Traversable as T
import qualified Data.Foldable as F
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Gen
data CList a = Empty
| CList [a] a [a]
empty :: CList a
empty = Empty
fromList :: [a] -> CList a
fromList [] = Empty
fromList a@(i:is) = let len = length a
(r,l) = splitAt (len `div` 2) is
in CList (reverse l) i r
singleton :: a -> CList a
singleton a = CList [] a []
update :: a -> CList a -> CList a
update v Empty = CList [] v []
update v (CList l _ r) = CList l v r
reverseDirection :: CList a -> CList a
reverseDirection Empty = Empty
reverseDirection (CList l f r) = CList r f l
leftElements :: CList a -> [a]
leftElements Empty = []
leftElements (CList l f r) = f : (l ++ (reverse r))
rightElements :: CList a -> [a]
rightElements Empty = []
rightElements (CList l f r) = f : (r ++ (reverse l))
toList :: CList a -> [a]
toList = rightElements
toInfList :: CList a -> [a]
toInfList = cycle . toList
focus :: CList a -> Maybe a
focus Empty = Nothing
focus (CList _ f _) = Just f
insertR :: a -> CList a -> CList a
insertR i Empty = CList [] i []
insertR i (CList l f r) = CList l i (f:r)
insertL :: a -> CList a -> CList a
insertL i Empty = CList [] i []
insertL i (CList l f r) = CList (f:l) i r
removeL :: CList a -> CList a
removeL Empty = Empty
removeL (CList [] _ []) = Empty
removeL (CList (l:ls) _ rs) = CList ls l rs
removeL (CList [] _ rs) = let (f:ls) = reverse rs
in CList ls f []
removeR :: CList a -> CList a
removeR Empty = Empty
removeR (CList [] _ []) = Empty
removeR (CList l _ (r:rs)) = CList l r rs
removeR (CList l _ []) = let (f:rs) = reverse l
in CList [] f rs
allRotations :: CList a -> CList (CList a)
allRotations Empty = singleton Empty
allRotations cl = CList ls cl rs
where
ls = unfoldr (fmap (join (,)) . mRotL) cl
rs = unfoldr (fmap (join (,)) . mRotR) cl
rotL :: CList a -> CList a
rotL Empty = Empty
rotL r@(CList [] _ []) = r
rotL (CList (l:ls) f rs) = CList ls l (f:rs)
rotL (CList [] f rs) = let (l:ls) = reverse rs
in CList ls l [f]
mRotL :: CList a -> Maybe (CList a)
mRotL (CList (l:ls) f rs) = Just $ CList ls l (f:rs)
mRotL _ = Nothing
rotR :: CList a -> CList a
rotR Empty = Empty
rotR r@(CList [] _ []) = r
rotR (CList ls f (r:rs)) = CList (f:ls) r rs
rotR (CList ls f []) = let (r:rs) = reverse ls
in CList [f] r rs
mRotR :: CList a -> Maybe (CList a)
mRotR (CList ls f (r:rs)) = Just $ CList (f:ls) r rs
mRotR _ = Nothing
rotN :: Int -> CList a -> CList a
rotN _ Empty = Empty
rotN _ cl@(CList [] _ []) = cl
rotN n cl = iterate rot cl !! n'
where
n' = abs n
rot | n < 0 = rotL
| otherwise = rotR
rotNR :: Int -> CList a -> CList a
rotNR n cl
| n <= 0 = cl
| otherwise = rotN n cl
rotNL :: Int -> CList a -> CList a
rotNL n cl
| n <= 0 = cl
| otherwise = rotN (negate n) cl
rotateTo :: (Eq a) => a -> CList a -> Maybe (CList a)
rotateTo a = findRotateTo (a==)
findRotateTo :: (a -> Bool) -> CList a -> Maybe (CList a)
findRotateTo p = find (maybe False p . focus) . toList . allRotations
filterR :: (a -> Bool) -> CList a -> CList a
filterR = filterCL removeR
filterL :: (a -> Bool) -> CList a -> CList a
filterL = filterCL removeL
filterCL :: (CList a -> CList a) -> (a -> Bool) -> CList a -> CList a
filterCL _ _ Empty = Empty
filterCL rm p (CList l f r)
| p f = cl'
| otherwise = rm cl'
where
cl' = CList (filter p l) f (filter p r)
foldrR :: (a -> b -> b) -> b -> CList a -> b
foldrR = foldrCL rightElements
foldrL :: (a -> b -> b) -> b -> CList a -> b
foldrL = foldrCL leftElements
foldrCL :: (CList a -> [a]) -> (a -> b -> b) -> b -> CList a -> b
foldrCL toL f a = foldr f a . toL
foldlR :: (a -> b -> a) -> a -> CList b -> a
foldlR = foldlCL rightElements
foldlL :: (a -> b -> a) -> a -> CList b -> a
foldlL = foldlCL leftElements
foldlCL :: (CList b -> [b]) -> (a -> b -> a) -> a -> CList b -> a
foldlCL toL f a = foldl' f a . toL
balance :: CList a -> CList a
balance = fromList . toList
packL :: CList a -> CList a
packL Empty = Empty
packL (CList l f r) = CList (l ++ (reverse r)) f []
packR :: CList a -> CList a
packR Empty = Empty
packR (CList l f r) = CList [] f (r ++ (reverse l))
isEmpty :: CList a -> Bool
isEmpty Empty = True
isEmpty _ = False
size :: CList a -> Int
size Empty = 0
size (CList l _ r) = 1 + (length l) + (length r)
instance (Show a) => Show (CList a) where
showsPrec d cl = showParen (d > 10) $
showString "fromList " . shows (toList cl)
instance (Read a) => Read (CList a) where
readsPrec p = readParen (p > 10) $ \ r -> do
("fromList",s) <- lex r
(xs,t) <- reads s
return (fromList xs,t)
instance (Eq a) => Eq (CList a) where
a == b = any ((toList a ==) . toList) . toList $ allRotations b
instance (NFData a) => NFData (CList a) where
rnf Empty = ()
rnf (CList l f r) = rnf f
`seq` rnf l
`seq` rnf r
instance Arbitrary a => Arbitrary (CList a) where
arbitrary = frequency [(1, return Empty), (10, arbCList)]
where arbCList = do
l <- arbitrary
f <- arbitrary
r <- arbitrary
return $ CList l f r
shrink (CList l f r) = Empty : [ CList l' f' r' | l' <- shrink l,
f' <- shrink f,
r' <- shrink r]
shrink Empty = []
instance Functor CList where
fmap _ Empty = Empty
fmap fn (CList l f r) = (CList (fmap fn l) (fn f) (fmap fn r))
instance F.Foldable CList where
foldMap = T.foldMapDefault
instance T.Traversable CList where
traverse _ Empty = pure Empty
traverse g (CList l f r) = (\f' r' l' -> CList l' f' r') <$> g f
<*> T.traverse g r
<*> T.traverse g l