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