{-# LANGUAGE PatternGuards, BangPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Stream.Future.Skew -- Copyright : (C) 2008-2011 Edward Kmett, -- (C) 2004 Dave Menendez -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Edward Kmett -- Stability : provisional -- Portability : portable -- -- Anticausal streams implemented as non-empty skew binary random access lists -- -- The Applicative zips streams, but since these are potentially infinite -- this is stricter than would be desired. You almost always want ------------------------------------------------------------------------------ module Data.Stream.Future.Skew ( Future(..) , (<|) -- O(1) , cons , length -- O(log n) , head -- O(1) , tail -- O(1) , tails , last -- O(log n) , uncons -- O(1) , index -- O(log n) , drop -- O(log n) , dropWhile -- O(n) , indexed , from , break , span , split -- O(log n) , splitW -- O(log n) , repeat , replicate -- O(log n) , insert -- O(n) , insertBy , update , adjust -- O(log n) , fromList , toFuture ) where import Control.Applicative hiding (empty) import Control.Comonad import Data.Functor.Alt import Data.Functor.Apply import Data.Foldable hiding (toList) import Data.Traversable (Traversable, traverse) import qualified Data.Traversable as Traversable import Data.Semigroup hiding (Last) import Data.Semigroup.Foldable import Data.Semigroup.Traversable import Data.Monoid (Monoid(mappend)) import Prelude hiding (null, head, tail, drop, dropWhile, length, foldr, last, span, repeat, replicate, break) infixr 5 :<, <| data Complete a = Tip a | Bin {-# UNPACK #-} !Int a !(Complete a) !(Complete a) deriving Show instance Functor Complete where fmap f (Tip a) = Tip (f a) fmap f (Bin w a l r) = Bin w (f a) (fmap f l) (fmap f r) instance Extend Complete where extend f w@Tip {} = Tip (f w) extend f w@(Bin n _ l r) = Bin n (f w) (extend f l) (extend f r) instance Comonad Complete where extract (Tip a) = a extract (Bin _ a _ _) = a instance Foldable Complete where foldMap f (Tip a) = f a foldMap f (Bin _ a l r) = f a `mappend` foldMap f l `mappend` foldMap f r foldr f z (Tip a) = f a z foldr f z (Bin _ a l r) = f a (foldr f (foldr f z r) l) instance Foldable1 Complete where foldMap1 f (Tip a) = f a foldMap1 f (Bin _ a l r) = f a <> foldMap1 f l <> foldMap1 f r instance Traversable Complete where traverse f (Tip a) = Tip <$> f a traverse f (Bin n a l r) = Bin n <$> f a <*> traverse f l <*> traverse f r instance Traversable1 Complete where traverse1 f (Tip a) = Tip <$> f a traverse1 f (Bin n a l r) = Bin n <$> f a <.> traverse1 f l <.> traverse1 f r bin :: a -> Complete a -> Complete a -> Complete a bin a l r = Bin (1 + weight l + weight r) a l r {-# INLINE bin #-} weight :: Complete a -> Int weight Tip{} = 1 weight (Bin w _ _ _) = w {-# INLINE weight #-} -- A future is a non-empty skew binary random access list of nodes. -- The last node, however, is allowed to contain fewer values. data Future a = Last !(Complete a) | !(Complete a) :< Future a -- deriving Show instance Show a => Show (Future a) where showsPrec d as = showParen (d >= 10) $ showString "fromList " . showsPrec 11 (toList as) instance Functor Future where fmap f (t :< ts) = fmap f t :< fmap f ts fmap f (Last t) = Last (fmap f t) instance Extend Future where extend g (Last t) = Last (extendTree g t Last) extend g (t :< ts) = extendTree g t (:< ts) :< extend g ts instance Comonad Future where extract = head extendTree :: (Future a -> b) -> Complete a -> (Complete a -> Future a) -> Complete b extendTree g w@Tip{} f = Tip (g (f w)) extendTree g w@(Bin n _ l r) f = Bin n (g (f w)) (extendTree g l (:< f r)) (extendTree g r f) instance Apply Future where Last (Tip f) <.> as = singleton (f (extract as)) fs <.> Last (Tip a) = singleton (extract fs a) Last (Bin _ f lf rf) <.> Last (Bin _ a la ra) = f a <| (lf :< Last rf <.> la :< Last ra ) Last (Bin _ f lf rf) <.> Bin _ a la ra :< as = f a <| (lf :< Last rf <.> la :< ra :< as) Last (Bin _ f lf rf) <.> Tip a :< as = f a <| (lf :< Last rf <.> as ) Bin _ f lf rf :< fs <.> Last (Bin _ a la ra) = f a <| (lf :< rf :< fs <.> la :< Last ra ) Bin _ f lf rf :< fs <.> Tip a :< as = f a <| (lf :< rf :< fs <.> as ) Bin _ f lf rf :< fs <.> Bin _ a la ra :< as = f a <| (lf :< rf :< fs <.> la :< ra :< as) Tip f :< fs <.> Tip a :< as = f a <| (fs <.> as ) Tip f :< fs <.> Bin _ a la ra :< as = f a <| (fs <.> la :< ra :< as) Tip f :< fs <.> Last (Bin _ a la ra) = f a <| (fs <.> la :< Last ra ) instance Applicative Future where pure = repeat (<*>) = (<.>) instance Alt Future where as bs = foldr (<|) bs as instance Foldable Future where foldMap f (t :< ts) = foldMap f t `mappend` foldMap f ts foldMap f (Last t) = foldMap f t foldr f z (t :< ts) = foldr f (foldr f z ts) t foldr f z (Last t) = foldr f z t toList :: Future a -> [a] toList = foldr (:) [] instance Foldable1 Future where foldMap1 f (t :< ts) = foldMap1 f t <> foldMap1 f ts foldMap1 f (Last t) = foldMap1 f t instance Traversable Future where traverse f (t :< ts) = (:<) <$> traverse f t <*> traverse f ts traverse f (Last t) = Last <$> traverse f t instance Traversable1 Future where traverse1 f (t :< ts) = (:<) <$> traverse1 f t <.> traverse1 f ts traverse1 f (Last t) = Last <$> traverse1 f t repeat :: a -> Future a repeat a0 = go a0 (Tip a0) where go :: a -> Complete a -> Future a go a as | ass <- bin a as as = as :< go a ass {-# INLINE repeat #-} -- | /O(log n)/ replicate :: Int -> a -> Future a replicate n a | n <= 0 = error "replicate: non-positive argument" | otherwise = go 1 n a (Tip a) (\ _ r -> r) where -- invariants: -- tb is a complete tree of i nodes all equal to b -- 1 <= i = 2^m-1 <= j -- k accepts r such that 0 <= r < i go :: Int -> Int -> b -> Complete b -> (Int -> Future b -> r) -> r go !i !j b tb k | j >= i2p1 = go i2p1 j b (Bin i2p1 b tb tb) k' | j >= i2 = k (j - i2) (tb :< Last tb) | otherwise = k (j - i) (Last tb) where i2 = i * 2 i2p1 = i2 + 1 k' r xs | r >= i2 = k (r - i2) (tb :< tb :< xs) | r >= i = k (r - i) (tb :< xs) | otherwise = k r xs {-# INLINE replicate #-} mapWithIndex :: (Int -> a -> b) -> Future a -> Future b mapWithIndex f0 as0 = spine f0 0 as0 where spine f m (Last as) = Last (tree f m as) spine f m (a :< as) = tree f m a :< spine f (m + weight a) as tree f m (Tip a) = Tip (f m a) tree f m (Bin n a l r) = Bin n (f m a) (tree f (m + 1) l) (tree f (m + 1 + weight l) r) indexed :: Future a -> Future (Int, a) indexed = mapWithIndex (,) {-# INLINE indexed #-} from :: Num a => a -> Future a from a = mapWithIndex ((+) . fromIntegral) (pure a) {-# INLINE from #-} -- | /O(1)/ singleton :: a -> Future a singleton a = Last (Tip a) {-# INLINE singleton #-} -- | /O(log n)/. length :: Future a -> Int length (Last t) = weight t length (t :< ts) = weight t + length ts -- | /O(1)/ cons (<|) :: a -> Future a -> Future a a <| (l :< Last r) | weight l == weight r = Last (bin a l r) a <| (l :< r :< as) | weight l == weight r = bin a l r :< as a <| as = Tip a :< as {-# INLINE (<|) #-} cons :: a -> Future a -> Future a cons = (<|) {-# INLINE cons #-} -- | /O(1)/ head :: Future a -> a head (a :< _) = extract a head (Last a) = extract a {-# INLINE head #-} -- | /O(1)/. tail :: Future a -> Maybe (Future a) tail (Tip{} :< ts) = Just ts tail (Bin _ _ l r :< ts) = Just (l :< r :< ts) tail (Last Tip{}) = Nothing tail (Last (Bin _ _ l r)) = Just (l :< Last r) {-# INLINE tail #-} tails :: Future a -> Future (Future a) tails = duplicate {-# INLINE tails #-} -- | /O(log n)/. last :: Future a -> a last (_ :< as) = last as last (Last as) = go as where go (Tip a) = a go (Bin _ _ _ r) = go r -- | /O(1)/. uncons :: Future a -> (a, Maybe (Future a)) uncons (Last (Tip a)) = (a, Nothing) uncons (Last (Bin _ a l r)) = (a, Just (l :< Last r)) uncons (Tip a :< as) = (a, Just as) uncons (Bin _ a l r :< as) = (a, Just (l :< r :< as)) {-# INLINE uncons #-} -- | /O(log n)/. index :: Int -> Future a -> a index i (Last t) | i < weight t = indexComplete i t | otherwise = error "index: out of range" index i (t :< ts) | i < w = indexComplete i t | otherwise = index (i - w) ts where w = weight t indexComplete :: Int -> Complete a -> a indexComplete 0 (Tip a) = a indexComplete i (Bin w a l r) | i == 0 = a | i <= w' = indexComplete (i-1) l | otherwise = indexComplete (i-1-w') r where w' = div w 2 indexComplete _ _ = error "index: index out of range" -- | /O(log n)/. drop :: Int -> Future a -> Maybe (Future a) drop 0 ts = Just ts drop i (t :< ts) = case compare i w of LT -> Just (dropComplete i t (:< ts)) EQ -> Just ts GT -> drop (i - w) ts where w = weight t drop i (Last t) | i < w = Just (dropComplete i t Last) | otherwise = Nothing where w = weight t dropComplete :: Int -> Complete a -> (Complete a -> Future a) -> Future a dropComplete 0 t f = f t dropComplete 1 (Bin _ _ l r) f = l :< f r dropComplete i (Bin w _ l r) f = case compare (i - 1) w' of LT -> dropComplete (i-1) l (:< f r) EQ -> f r GT -> dropComplete (i-1-w') r f where w' = div w 2 dropComplete _ _ _ = error "drop: index out of range" -- /O(n)/. dropWhile :: (a -> Bool) -> Future a -> Maybe (Future a) dropWhile p as | p (head as) = tail as >>= dropWhile p | otherwise = Just as -- /O(n)/ span :: (a -> Bool) -> Future a -> ([a], Maybe (Future a)) span p aas = case uncons aas of (a, Just as) | p a, (ts, fs) <- span p as -> (a:ts, fs) (a, Nothing) | p a -> ([a], Nothing) (_, _) -> ([], Just aas) -- /O(n)/ break :: (a -> Bool) -> Future a -> ([a], Maybe (Future a)) break p = span (not . p) -- /(O(n), O(log n))/ split at _some_ edge where function goes from False to True. -- best used with a monotonic function split :: (a -> Bool) -> Future a -> ([a], Maybe (Future a)) split p l@(Last a) | p (extract a) = ([], Just l) | otherwise = splitComplete p a Last split p (a :< as) | p (extract as) = splitComplete p a (:< as) | (ts, fs) <- split p as = (foldr (:) ts a, fs) -- for use when we know the split occurs within a given tree splitComplete :: (a -> Bool) -> Complete a -> (Complete a -> Future a) -> ([a], Maybe (Future a)) splitComplete p t@(Tip a) f | p a = ([], Just (f t)) | otherwise = ([a], Nothing) splitComplete p t@(Bin _ a l r) f | p a = ([], Just (f t)) | p (extract r), (ts, fs) <- splitComplete p l (:< f r) = (a:ts, fs) | (ts, fs) <- splitComplete p r f = (a:foldr (:) ts l, fs) -- /(O(n), O(log n))/ split at _some_ edge where function goes from False to True. -- best used with a monotonic function -- -- > splitW p xs = (map extract &&& fmap (fmap extract)) . split p . duplicate splitW :: (Future a -> Bool) -> Future a -> ([a], Maybe (Future a)) splitW p l@(Last a) | p l = ([], Just l) | otherwise = splitCompleteW p a Last splitW p (a :< as) | p as = splitCompleteW p a (:< as) | (ts, fs) <- splitW p as = (foldr (:) ts a, fs) -- for use when we know the split occurs within a given tree splitCompleteW :: (Future a -> Bool) -> Complete a -> (Complete a -> Future a) -> ([a], Maybe (Future a)) splitCompleteW p t@(Tip a) f | w <- f t, p w = ([], Just w) | otherwise = ([a], Nothing) splitCompleteW p t@(Bin _ a l r) f | w <- f t, p w = ([], Just w) | w <- f r, p w, (ts, fs) <- splitCompleteW p l (:< w) = (a:ts, fs) | (ts, fs) <- splitCompleteW p r f = (a:foldr (:) ts l, fs) fromList :: [a] -> Future a fromList [] = error "fromList: empty list" fromList (x:xs) = go x xs where go a [] = singleton a go a (b:bs) = a <| go b bs toFuture :: [a] -> Maybe (Future a) toFuture [] = Nothing toFuture xs = Just (fromList xs) -- /O(n)/ insert :: Ord a => a -> Future a -> Future a insert a as = case split (a<=) as of (_, Nothing) -> foldr (<|) (singleton a) as (ts, Just as') -> foldr (<|) (a <| as') ts -- /O(n)/. Finds the split in O(log n), but then has to recons insertBy :: (a -> a -> Ordering) -> a -> Future a -> Future a insertBy cmp a as = case split (\b -> cmp a b <= EQ) as of (_, Nothing) -> foldr (<|) (singleton a) as (ts, Just as') -> foldr (<|) (a <| as') ts -- /O(log n)/ Change the value of the nth entry in the future adjust :: Int -> (a -> a) -> Future a -> Future a adjust !n f d@(Last a) | n < weight a = Last (adjustComplete n f a) | otherwise = d adjust !n f (a :< as) | n < w = adjustComplete n f a :< as | otherwise = a :< adjust (n - w) f as where w = weight a adjustComplete :: Int -> (a -> a) -> Complete a -> Complete a adjustComplete 0 f (Tip a) = Tip (f a) adjustComplete _ _ t@Tip{} = t adjustComplete n f (Bin m a l r) | n == 0 = Bin m (f a) l r | n < w = Bin m a (adjustComplete (n - 1) f l) r | otherwise = Bin m a l (adjustComplete (n - 1 - w) f r) where w = weight l update :: Int -> a -> Future a -> Future a update n = adjust n . const