module Data.CappedList
( CappedList (..)
, toList
, toList_
, fromList
, null
, appendR
, appendL
, appendR_
, appendL_
, appendWith
, map
, mapEither
, concatMapM
, foldr
, foldl
, unfoldr
, length
) where
import Prelude hiding (null, map, foldl, foldr, length)
import qualified Prelude as Prelude
import Data.Monoid (Monoid, mempty, mappend)
import Control.Monad (MonadPlus, mzero, mplus, ap)
import Control.Monad.Fix (MonadFix, fix, mfix)
import qualified Control.Applicative as A
import Control.Applicative ((<$>), (<*>))
import qualified Data.Foldable as F
import qualified Data.Traversable as T
import Data.Data (Data)
import Data.Typeable (Typeable)
data CappedList cap a
= Next a (CappedList cap a)
| Cap cap
deriving (Eq, Show, Data, Typeable)
instance Functor (CappedList cap) where
fmap = map
instance Monoid cap => Monoid (CappedList cap a) where
mempty = Cap mempty
mappend = appendWith mappend
instance Monoid cap => Monad (CappedList cap) where
(>>=) = flip concatMapM
return = flip Next (Cap mempty)
instance Monoid cap => MonadPlus (CappedList cap) where
mzero = mempty
mplus = mappend
instance Monoid cap => A.Applicative (CappedList cap) where
pure = return
(<*>) = ap
instance Monoid cap => A.Alternative (CappedList cap) where
empty = mempty
(<|>) = mappend
instance Monoid cap => F.Foldable (CappedList cap) where
foldMap = T.foldMapDefault
instance Monoid cap => T.Traversable (CappedList cap) where
sequenceA (Cap x) = A.pure $ Cap x
sequenceA (Next f fs) = Next <$> f <*> T.sequenceA fs
instance Monoid cap => MonadFix (CappedList cap) where
mfix f = case fix (f . head') of
Cap x -> Cap x
(Next x _) -> mappend (return x) (mfix (tail' . f))
toList :: CappedList cap a -> (cap, [a])
toList = foldl (\(cap, xs) x -> (cap, x:xs)) (\cap -> (cap, []))
toList_ :: CappedList cap a -> [a]
toList_ = foldr (:) (const [])
fromList :: [a] -> cap -> CappedList cap a
fromList [] = Cap
fromList (x:xs) = Next x . fromList xs
null :: CappedList cap a -> Bool
null (Next _ _) = False
null _ = True
appendL :: CappedList cap1 a -> CappedList cap2 a -> (cap2, CappedList cap1 a)
appendL xs (Cap y) = (y, xs)
appendL x@(Cap _) (Next y ys) = let (cap, z) = appendL x ys in (cap, Next y z)
appendL (Next x xs) ys = let (cap, z) = appendL xs ys in (cap, Next x z)
appendR :: CappedList cap1 a -> CappedList cap2 a -> (cap1, CappedList cap2 a)
appendR (Next x xs) ys = let (cap, z) = appendR xs ys in (cap, Next x z)
appendR (Cap x) ys = (x, ys)
appendL_ :: CappedList cap1 a -> CappedList cap2 a -> CappedList cap1 a
appendL_ xs (Cap _) = xs
appendL_ (Next x xs) ys = Next x (appendL_ xs ys)
appendL_ xs (Next y ys) = Next y (appendL_ xs ys)
appendR_ :: CappedList cap1 a -> CappedList cap2 a -> CappedList cap2 a
appendR_ (Next x xs) = Next x . appendR_ xs
appendR_ _ = id
appendWith :: (c -> d -> e) -> CappedList c a -> CappedList d a
-> CappedList e a
appendWith f (Cap x) (Cap y) = Cap (f x y)
appendWith f (Next x xs) ys = Next x (appendWith f xs ys)
appendWith f xs (Next y ys) = Next y (appendWith f xs ys)
map :: (a -> b) -> CappedList cap a -> CappedList cap b
map f = foldr (Next . f) Cap
mapEither :: (a -> Either cap b) -> CappedList cap a -> CappedList cap b
mapEither f = foldr (\a acc -> either Cap (flip Next acc) (f a)) Cap
concatMapM :: Monoid cap => (a -> CappedList cap b) -> CappedList cap a
-> CappedList cap b
concatMapM f = foldr (mappend . f) Cap
foldr :: (a -> b -> b) -> (cap -> b) -> CappedList cap a -> b
foldr f z = foldr' where
foldr' (Cap x) = z x
foldr' (Next x xs) = f x (foldr' xs)
foldl :: (b -> a -> b) -> (cap -> b) -> CappedList cap a -> b
foldl f = foldl' where
foldl' z (Cap x) = z x
foldl' z (Next x xs) = foldl' (\cap -> f (z cap) x) xs
unfoldr :: (b -> Either cap (a, b)) -> b -> CappedList cap a
unfoldr f = unfoldr' where
unfoldr' x = case f x of
Left cap -> Cap cap
Right (a, b) -> Next a (unfoldr' b)
length :: CappedList cap a -> Int
length = foldr (const (1 +)) (const 0)
head' :: CappedList cap a -> a
head' (Cap _) = error "mfix CappedList: Cap"
head' (Next x _) = x
tail' :: CappedList cap a -> CappedList cap a
tail' (Cap _) = error "mfix CappedList: Cap"
tail' (Next _ xs) = xs