1{-# LANGUAGE CPP, FlexibleInstances, Rank2Types, BangPatterns #-} 2 3-- | 4-- Module : Data.Vector.Fusion.Bundle 5-- Copyright : (c) Roman Leshchinskiy 2008-2010 6-- License : BSD-style 7-- 8-- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au> 9-- Stability : experimental 10-- Portability : non-portable 11-- 12-- Bundles for stream fusion 13-- 14 15module Data.Vector.Fusion.Bundle ( 16 -- * Types 17 Step(..), Chunk(..), Bundle, MBundle, 18 19 -- * In-place markers 20 inplace, 21 22 -- * Size hints 23 size, sized, 24 25 -- * Length information 26 length, null, 27 28 -- * Construction 29 empty, singleton, cons, snoc, replicate, generate, (++), 30 31 -- * Accessing individual elements 32 head, last, (!!), (!?), 33 34 -- * Substreams 35 slice, init, tail, take, drop, 36 37 -- * Mapping 38 map, concatMap, flatten, unbox, 39 40 -- * Zipping 41 indexed, indexedR, 42 zipWith, zipWith3, zipWith4, zipWith5, zipWith6, 43 zip, zip3, zip4, zip5, zip6, 44 45 -- * Filtering 46 filter, takeWhile, dropWhile, 47 48 -- * Searching 49 elem, notElem, find, findIndex, 50 51 -- * Folding 52 foldl, foldl1, foldl', foldl1', foldr, foldr1, 53 54 -- * Specialised folds 55 and, or, 56 57 -- * Unfolding 58 unfoldr, unfoldrN, iterateN, 59 60 -- * Scans 61 prescanl, prescanl', 62 postscanl, postscanl', 63 scanl, scanl', 64 scanl1, scanl1', 65 66 -- * Enumerations 67 enumFromStepN, enumFromTo, enumFromThenTo, 68 69 -- * Conversions 70 toList, fromList, fromListN, unsafeFromList, lift, 71 fromVector, reVector, fromVectors, concatVectors, 72 73 -- * Monadic combinators 74 mapM, mapM_, zipWithM, zipWithM_, filterM, foldM, fold1M, foldM', fold1M', 75 76 eq, cmp, eqBy, cmpBy 77) where 78 79import Data.Vector.Generic.Base ( Vector ) 80import Data.Vector.Fusion.Bundle.Size 81import Data.Vector.Fusion.Util 82import Data.Vector.Fusion.Stream.Monadic ( Stream(..), Step(..) ) 83import Data.Vector.Fusion.Bundle.Monadic ( Chunk(..) ) 84import qualified Data.Vector.Fusion.Bundle.Monadic as M 85import qualified Data.Vector.Fusion.Stream.Monadic as S 86 87import Prelude hiding ( length, null, 88 replicate, (++), 89 head, last, (!!), 90 init, tail, take, drop, 91 map, concatMap, 92 zipWith, zipWith3, zip, zip3, 93 filter, takeWhile, dropWhile, 94 elem, notElem, 95 foldl, foldl1, foldr, foldr1, 96 and, or, 97 scanl, scanl1, 98 enumFromTo, enumFromThenTo, 99 mapM, mapM_ ) 100 101#if MIN_VERSION_base(4,9,0) 102import Data.Functor.Classes (Eq1 (..), Ord1 (..)) 103#endif 104 105import GHC.Base ( build ) 106 107-- Data.Vector.Internal.Check is unused 108#define NOT_VECTOR_MODULE 109#include "vector.h" 110 111-- | The type of pure streams 112type Bundle = M.Bundle Id 113 114-- | Alternative name for monadic streams 115type MBundle = M.Bundle 116 117inplace :: (forall m. Monad m => S.Stream m a -> S.Stream m b) 118 -> (Size -> Size) -> Bundle v a -> Bundle v b 119{-# INLINE_FUSED inplace #-} 120inplace f g b = b `seq` M.fromStream (f (M.elements b)) (g (M.size b)) 121 122{-# RULES 123 124"inplace/inplace [Vector]" 125 forall (f1 :: forall m. Monad m => S.Stream m a -> S.Stream m a) 126 (f2 :: forall m. Monad m => S.Stream m a -> S.Stream m a) 127 g1 g2 s. 128 inplace f1 g1 (inplace f2 g2 s) = inplace (f1 . f2) (g1 . g2) s #-} 129 130 131 132-- | Convert a pure stream to a monadic stream 133lift :: Monad m => Bundle v a -> M.Bundle m v a 134{-# INLINE_FUSED lift #-} 135lift (M.Bundle (Stream step s) (Stream vstep t) v sz) 136 = M.Bundle (Stream (return . unId . step) s) 137 (Stream (return . unId . vstep) t) v sz 138 139-- | 'Size' hint of a 'Bundle' 140size :: Bundle v a -> Size 141{-# INLINE size #-} 142size = M.size 143 144-- | Attach a 'Size' hint to a 'Bundle' 145sized :: Bundle v a -> Size -> Bundle v a 146{-# INLINE sized #-} 147sized = M.sized 148 149-- Length 150-- ------ 151 152-- | Length of a 'Bundle' 153length :: Bundle v a -> Int 154{-# INLINE length #-} 155length = unId . M.length 156 157-- | Check if a 'Bundle' is empty 158null :: Bundle v a -> Bool 159{-# INLINE null #-} 160null = unId . M.null 161 162-- Construction 163-- ------------ 164 165-- | Empty 'Bundle' 166empty :: Bundle v a 167{-# INLINE empty #-} 168empty = M.empty 169 170-- | Singleton 'Bundle' 171singleton :: a -> Bundle v a 172{-# INLINE singleton #-} 173singleton = M.singleton 174 175-- | Replicate a value to a given length 176replicate :: Int -> a -> Bundle v a 177{-# INLINE replicate #-} 178replicate = M.replicate 179 180-- | Generate a stream from its indices 181generate :: Int -> (Int -> a) -> Bundle v a 182{-# INLINE generate #-} 183generate = M.generate 184 185-- | Prepend an element 186cons :: a -> Bundle v a -> Bundle v a 187{-# INLINE cons #-} 188cons = M.cons 189 190-- | Append an element 191snoc :: Bundle v a -> a -> Bundle v a 192{-# INLINE snoc #-} 193snoc = M.snoc 194 195infixr 5 ++ 196-- | Concatenate two 'Bundle's 197(++) :: Bundle v a -> Bundle v a -> Bundle v a 198{-# INLINE (++) #-} 199(++) = (M.++) 200 201-- Accessing elements 202-- ------------------ 203 204-- | First element of the 'Bundle' or error if empty 205head :: Bundle v a -> a 206{-# INLINE head #-} 207head = unId . M.head 208 209-- | Last element of the 'Bundle' or error if empty 210last :: Bundle v a -> a 211{-# INLINE last #-} 212last = unId . M.last 213 214infixl 9 !! 215-- | Element at the given position 216(!!) :: Bundle v a -> Int -> a 217{-# INLINE (!!) #-} 218s !! i = unId (s M.!! i) 219 220infixl 9 !? 221-- | Element at the given position or 'Nothing' if out of bounds 222(!?) :: Bundle v a -> Int -> Maybe a 223{-# INLINE (!?) #-} 224s !? i = unId (s M.!? i) 225 226-- Substreams 227-- ---------- 228 229-- | Extract a substream of the given length starting at the given position. 230slice :: Int -- ^ starting index 231 -> Int -- ^ length 232 -> Bundle v a 233 -> Bundle v a 234{-# INLINE slice #-} 235slice = M.slice 236 237-- | All but the last element 238init :: Bundle v a -> Bundle v a 239{-# INLINE init #-} 240init = M.init 241 242-- | All but the first element 243tail :: Bundle v a -> Bundle v a 244{-# INLINE tail #-} 245tail = M.tail 246 247-- | The first @n@ elements 248take :: Int -> Bundle v a -> Bundle v a 249{-# INLINE take #-} 250take = M.take 251 252-- | All but the first @n@ elements 253drop :: Int -> Bundle v a -> Bundle v a 254{-# INLINE drop #-} 255drop = M.drop 256 257-- Mapping 258-- --------------- 259 260-- | Map a function over a 'Bundle' 261map :: (a -> b) -> Bundle v a -> Bundle v b 262{-# INLINE map #-} 263map = M.map 264 265unbox :: Bundle v (Box a) -> Bundle v a 266{-# INLINE unbox #-} 267unbox = M.unbox 268 269concatMap :: (a -> Bundle v b) -> Bundle v a -> Bundle v b 270{-# INLINE concatMap #-} 271concatMap = M.concatMap 272 273-- Zipping 274-- ------- 275 276-- | Pair each element in a 'Bundle' with its index 277indexed :: Bundle v a -> Bundle v (Int,a) 278{-# INLINE indexed #-} 279indexed = M.indexed 280 281-- | Pair each element in a 'Bundle' with its index, starting from the right 282-- and counting down 283indexedR :: Int -> Bundle v a -> Bundle v (Int,a) 284{-# INLINE_FUSED indexedR #-} 285indexedR = M.indexedR 286 287-- | Zip two 'Bundle's with the given function 288zipWith :: (a -> b -> c) -> Bundle v a -> Bundle v b -> Bundle v c 289{-# INLINE zipWith #-} 290zipWith = M.zipWith 291 292-- | Zip three 'Bundle's with the given function 293zipWith3 :: (a -> b -> c -> d) -> Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 294{-# INLINE zipWith3 #-} 295zipWith3 = M.zipWith3 296 297zipWith4 :: (a -> b -> c -> d -> e) 298 -> Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 299 -> Bundle v e 300{-# INLINE zipWith4 #-} 301zipWith4 = M.zipWith4 302 303zipWith5 :: (a -> b -> c -> d -> e -> f) 304 -> Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 305 -> Bundle v e -> Bundle v f 306{-# INLINE zipWith5 #-} 307zipWith5 = M.zipWith5 308 309zipWith6 :: (a -> b -> c -> d -> e -> f -> g) 310 -> Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 311 -> Bundle v e -> Bundle v f -> Bundle v g 312{-# INLINE zipWith6 #-} 313zipWith6 = M.zipWith6 314 315zip :: Bundle v a -> Bundle v b -> Bundle v (a,b) 316{-# INLINE zip #-} 317zip = M.zip 318 319zip3 :: Bundle v a -> Bundle v b -> Bundle v c -> Bundle v (a,b,c) 320{-# INLINE zip3 #-} 321zip3 = M.zip3 322 323zip4 :: Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 324 -> Bundle v (a,b,c,d) 325{-# INLINE zip4 #-} 326zip4 = M.zip4 327 328zip5 :: Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 329 -> Bundle v e -> Bundle v (a,b,c,d,e) 330{-# INLINE zip5 #-} 331zip5 = M.zip5 332 333zip6 :: Bundle v a -> Bundle v b -> Bundle v c -> Bundle v d 334 -> Bundle v e -> Bundle v f -> Bundle v (a,b,c,d,e,f) 335{-# INLINE zip6 #-} 336zip6 = M.zip6 337 338-- Filtering 339-- --------- 340 341-- | Drop elements which do not satisfy the predicate 342filter :: (a -> Bool) -> Bundle v a -> Bundle v a 343{-# INLINE filter #-} 344filter = M.filter 345 346-- | Longest prefix of elements that satisfy the predicate 347takeWhile :: (a -> Bool) -> Bundle v a -> Bundle v a 348{-# INLINE takeWhile #-} 349takeWhile = M.takeWhile 350 351-- | Drop the longest prefix of elements that satisfy the predicate 352dropWhile :: (a -> Bool) -> Bundle v a -> Bundle v a 353{-# INLINE dropWhile #-} 354dropWhile = M.dropWhile 355 356-- Searching 357-- --------- 358 359infix 4 `elem` 360-- | Check whether the 'Bundle' contains an element 361elem :: Eq a => a -> Bundle v a -> Bool 362{-# INLINE elem #-} 363elem x = unId . M.elem x 364 365infix 4 `notElem` 366-- | Inverse of `elem` 367notElem :: Eq a => a -> Bundle v a -> Bool 368{-# INLINE notElem #-} 369notElem x = unId . M.notElem x 370 371-- | Yield 'Just' the first element matching the predicate or 'Nothing' if no 372-- such element exists. 373find :: (a -> Bool) -> Bundle v a -> Maybe a 374{-# INLINE find #-} 375find f = unId . M.find f 376 377-- | Yield 'Just' the index of the first element matching the predicate or 378-- 'Nothing' if no such element exists. 379findIndex :: (a -> Bool) -> Bundle v a -> Maybe Int 380{-# INLINE findIndex #-} 381findIndex f = unId . M.findIndex f 382 383-- Folding 384-- ------- 385 386-- | Left fold 387foldl :: (a -> b -> a) -> a -> Bundle v b -> a 388{-# INLINE foldl #-} 389foldl f z = unId . M.foldl f z 390 391-- | Left fold on non-empty 'Bundle's 392foldl1 :: (a -> a -> a) -> Bundle v a -> a 393{-# INLINE foldl1 #-} 394foldl1 f = unId . M.foldl1 f 395 396-- | Left fold with strict accumulator 397foldl' :: (a -> b -> a) -> a -> Bundle v b -> a 398{-# INLINE foldl' #-} 399foldl' f z = unId . M.foldl' f z 400 401-- | Left fold on non-empty 'Bundle's with strict accumulator 402foldl1' :: (a -> a -> a) -> Bundle v a -> a 403{-# INLINE foldl1' #-} 404foldl1' f = unId . M.foldl1' f 405 406-- | Right fold 407foldr :: (a -> b -> b) -> b -> Bundle v a -> b 408{-# INLINE foldr #-} 409foldr f z = unId . M.foldr f z 410 411-- | Right fold on non-empty 'Bundle's 412foldr1 :: (a -> a -> a) -> Bundle v a -> a 413{-# INLINE foldr1 #-} 414foldr1 f = unId . M.foldr1 f 415 416-- Specialised folds 417-- ----------------- 418 419and :: Bundle v Bool -> Bool 420{-# INLINE and #-} 421and = unId . M.and 422 423or :: Bundle v Bool -> Bool 424{-# INLINE or #-} 425or = unId . M.or 426 427-- Unfolding 428-- --------- 429 430-- | Unfold 431unfoldr :: (s -> Maybe (a, s)) -> s -> Bundle v a 432{-# INLINE unfoldr #-} 433unfoldr = M.unfoldr 434 435-- | Unfold at most @n@ elements 436unfoldrN :: Int -> (s -> Maybe (a, s)) -> s -> Bundle v a 437{-# INLINE unfoldrN #-} 438unfoldrN = M.unfoldrN 439 440-- | Apply function n-1 times to value. Zeroth element is original value. 441iterateN :: Int -> (a -> a) -> a -> Bundle v a 442{-# INLINE iterateN #-} 443iterateN = M.iterateN 444 445-- Scans 446-- ----- 447 448-- | Prefix scan 449prescanl :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 450{-# INLINE prescanl #-} 451prescanl = M.prescanl 452 453-- | Prefix scan with strict accumulator 454prescanl' :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 455{-# INLINE prescanl' #-} 456prescanl' = M.prescanl' 457 458-- | Suffix scan 459postscanl :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 460{-# INLINE postscanl #-} 461postscanl = M.postscanl 462 463-- | Suffix scan with strict accumulator 464postscanl' :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 465{-# INLINE postscanl' #-} 466postscanl' = M.postscanl' 467 468-- | Haskell-style scan 469scanl :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 470{-# INLINE scanl #-} 471scanl = M.scanl 472 473-- | Haskell-style scan with strict accumulator 474scanl' :: (a -> b -> a) -> a -> Bundle v b -> Bundle v a 475{-# INLINE scanl' #-} 476scanl' = M.scanl' 477 478-- | Scan over a non-empty 'Bundle' 479scanl1 :: (a -> a -> a) -> Bundle v a -> Bundle v a 480{-# INLINE scanl1 #-} 481scanl1 = M.scanl1 482 483-- | Scan over a non-empty 'Bundle' with a strict accumulator 484scanl1' :: (a -> a -> a) -> Bundle v a -> Bundle v a 485{-# INLINE scanl1' #-} 486scanl1' = M.scanl1' 487 488 489-- Comparisons 490-- ----------- 491 492-- | Check if two 'Bundle's are equal 493eq :: (Eq a) => Bundle v a -> Bundle v a -> Bool 494{-# INLINE eq #-} 495eq = eqBy (==) 496 497eqBy :: (a -> b -> Bool) -> Bundle v a -> Bundle v b -> Bool 498{-# INLINE eqBy #-} 499eqBy e x y = unId (M.eqBy e x y) 500 501-- | Lexicographically compare two 'Bundle's 502cmp :: (Ord a) => Bundle v a -> Bundle v a -> Ordering 503{-# INLINE cmp #-} 504cmp = cmpBy compare 505 506cmpBy :: (a -> b -> Ordering) -> Bundle v a -> Bundle v b -> Ordering 507{-# INLINE cmpBy #-} 508cmpBy c x y = unId (M.cmpBy c x y) 509 510instance Eq a => Eq (M.Bundle Id v a) where 511 {-# INLINE (==) #-} 512 (==) = eq 513 514instance Ord a => Ord (M.Bundle Id v a) where 515 {-# INLINE compare #-} 516 compare = cmp 517 518#if MIN_VERSION_base(4,9,0) 519instance Eq1 (M.Bundle Id v) where 520 {-# INLINE liftEq #-} 521 liftEq = eqBy 522 523instance Ord1 (M.Bundle Id v) where 524 {-# INLINE liftCompare #-} 525 liftCompare = cmpBy 526#endif 527 528-- Monadic combinators 529-- ------------------- 530 531-- | Apply a monadic action to each element of the stream, producing a monadic 532-- stream of results 533mapM :: Monad m => (a -> m b) -> Bundle v a -> M.Bundle m v b 534{-# INLINE mapM #-} 535mapM f = M.mapM f . lift 536 537-- | Apply a monadic action to each element of the stream 538mapM_ :: Monad m => (a -> m b) -> Bundle v a -> m () 539{-# INLINE mapM_ #-} 540mapM_ f = M.mapM_ f . lift 541 542zipWithM :: Monad m => (a -> b -> m c) -> Bundle v a -> Bundle v b -> M.Bundle m v c 543{-# INLINE zipWithM #-} 544zipWithM f as bs = M.zipWithM f (lift as) (lift bs) 545 546zipWithM_ :: Monad m => (a -> b -> m c) -> Bundle v a -> Bundle v b -> m () 547{-# INLINE zipWithM_ #-} 548zipWithM_ f as bs = M.zipWithM_ f (lift as) (lift bs) 549 550-- | Yield a monadic stream of elements that satisfy the monadic predicate 551filterM :: Monad m => (a -> m Bool) -> Bundle v a -> M.Bundle m v a 552{-# INLINE filterM #-} 553filterM f = M.filterM f . lift 554 555-- | Monadic fold 556foldM :: Monad m => (a -> b -> m a) -> a -> Bundle v b -> m a 557{-# INLINE foldM #-} 558foldM m z = M.foldM m z . lift 559 560-- | Monadic fold over non-empty stream 561fold1M :: Monad m => (a -> a -> m a) -> Bundle v a -> m a 562{-# INLINE fold1M #-} 563fold1M m = M.fold1M m . lift 564 565-- | Monadic fold with strict accumulator 566foldM' :: Monad m => (a -> b -> m a) -> a -> Bundle v b -> m a 567{-# INLINE foldM' #-} 568foldM' m z = M.foldM' m z . lift 569 570-- | Monad fold over non-empty stream with strict accumulator 571fold1M' :: Monad m => (a -> a -> m a) -> Bundle v a -> m a 572{-# INLINE fold1M' #-} 573fold1M' m = M.fold1M' m . lift 574 575-- Enumerations 576-- ------------ 577 578-- | Yield a 'Bundle' of the given length containing the values @x@, @x+y@, 579-- @x+y+y@ etc. 580enumFromStepN :: Num a => a -> a -> Int -> Bundle v a 581{-# INLINE enumFromStepN #-} 582enumFromStepN = M.enumFromStepN 583 584-- | Enumerate values 585-- 586-- /WARNING:/ This operations can be very inefficient. If at all possible, use 587-- 'enumFromStepN' instead. 588enumFromTo :: Enum a => a -> a -> Bundle v a 589{-# INLINE enumFromTo #-} 590enumFromTo = M.enumFromTo 591 592-- | Enumerate values with a given step. 593-- 594-- /WARNING:/ This operations is very inefficient. If at all possible, use 595-- 'enumFromStepN' instead. 596enumFromThenTo :: Enum a => a -> a -> a -> Bundle v a 597{-# INLINE enumFromThenTo #-} 598enumFromThenTo = M.enumFromThenTo 599 600-- Conversions 601-- ----------- 602 603-- | Convert a 'Bundle' to a list 604toList :: Bundle v a -> [a] 605{-# INLINE toList #-} 606-- toList s = unId (M.toList s) 607toList s = build (\c n -> toListFB c n s) 608 609-- This supports foldr/build list fusion that GHC implements 610toListFB :: (a -> b -> b) -> b -> Bundle v a -> b 611{-# INLINE [0] toListFB #-} 612toListFB c n M.Bundle{M.sElems = Stream step t} = go t 613 where 614 go s = case unId (step s) of 615 Yield x s' -> x `c` go s' 616 Skip s' -> go s' 617 Done -> n 618 619-- | Create a 'Bundle' from a list 620fromList :: [a] -> Bundle v a 621{-# INLINE fromList #-} 622fromList = M.fromList 623 624-- | Create a 'Bundle' from the first @n@ elements of a list 625-- 626-- > fromListN n xs = fromList (take n xs) 627fromListN :: Int -> [a] -> Bundle v a 628{-# INLINE fromListN #-} 629fromListN = M.fromListN 630 631unsafeFromList :: Size -> [a] -> Bundle v a 632{-# INLINE unsafeFromList #-} 633unsafeFromList = M.unsafeFromList 634 635fromVector :: Vector v a => v a -> Bundle v a 636{-# INLINE fromVector #-} 637fromVector = M.fromVector 638 639reVector :: Bundle u a -> Bundle v a 640{-# INLINE reVector #-} 641reVector = M.reVector 642 643fromVectors :: Vector v a => [v a] -> Bundle v a 644{-# INLINE fromVectors #-} 645fromVectors = M.fromVectors 646 647concatVectors :: Vector v a => Bundle u (v a) -> Bundle v a 648{-# INLINE concatVectors #-} 649concatVectors = M.concatVectors 650 651-- | Create a 'Bundle' of values from a 'Bundle' of streamable things 652flatten :: (a -> s) -> (s -> Step s b) -> Size -> Bundle v a -> Bundle v b 653{-# INLINE_FUSED flatten #-} 654flatten mk istep sz = M.flatten (return . mk) (return . istep) sz . lift 655 656