on d161b05 help sign in
streamly/benchmark/LinearOps.hs
677 lines 22 kB history raw
1-- |
2-- Module : BenchmarkOps
3-- Copyright : (c) 2018 Harendra Kumar
4--
5-- License : MIT
6-- Maintainer : harendra.kumar@gmail.com
8{-# LANGUAGE CPP #-}
9{-# LANGUAGE FlexibleContexts #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE DeriveAnyClass #-}
12{-# LANGUAGE DeriveGeneric #-}
14module LinearOps where
16import Control.Monad (when)
17import Control.Monad.IO.Class (MonadIO)
18import Data.Functor.Identity (Identity, runIdentity)
19import Data.Maybe (fromJust)
20import Prelude
21 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (>=),
22 subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
23 maxBound, div, IO, compare, Double, fromIntegral, Integer, (<$>),
24 (<*>), flip, (**), (/))
25import qualified Prelude as P
26import qualified Data.Foldable as F
27import qualified GHC.Exts as GHC
28import Control.DeepSeq (NFData)
29import GHC.Generics (Generic)
31import qualified Streamly as S hiding (foldMapWith, runStream)
32import qualified Streamly.Prelude as S
33-- import qualified Streamly.Pipe as Pipe
35value, maxValue, value2 :: Int
36#ifdef LINEAR_ASYNC
37value = 10000
38#else
39value = 100000
40#endif
41maxValue = value + 1
42value2 = P.round (P.fromIntegral value**(1/2::P.Double)) -- double nested loop
44-------------------------------------------------------------------------------
45-- Benchmark ops
46-------------------------------------------------------------------------------
48-------------------------------------------------------------------------------
49-- Stream generation and elimination
50-------------------------------------------------------------------------------
52type Stream m a = S.SerialT m a
54{-# INLINE source #-}
55source :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
56source n = sourceUnfoldrM n
58{-# INLINE sourceIntFromTo #-}
59sourceIntFromTo :: (Monad m, S.IsStream t) => Int -> t m Int
60sourceIntFromTo n = S.enumerateFromTo n (n + value)
62{-# INLINE sourceIntFromThenTo #-}
63sourceIntFromThenTo :: (Monad m, S.IsStream t) => Int -> t m Int
64sourceIntFromThenTo n = S.enumerateFromThenTo n (n + 1) (n + value)
66{-# INLINE sourceFracFromTo #-}
67sourceFracFromTo :: (Monad m, S.IsStream t) => Int -> t m Double
68sourceFracFromTo n =
69 S.enumerateFromTo (fromIntegral n) (fromIntegral (n + value))
71{-# INLINE sourceFracFromThenTo #-}
72sourceFracFromThenTo :: (Monad m, S.IsStream t) => Int -> t m Double
73sourceFracFromThenTo n = S.enumerateFromThenTo (fromIntegral n)
74 (fromIntegral n + 1.0001) (fromIntegral (n + value))
76{-# INLINE sourceIntegerFromStep #-}
77sourceIntegerFromStep :: (Monad m, S.IsStream t) => Int -> t m Integer
78sourceIntegerFromStep n =
79 S.take value $ S.enumerateFromThen (fromIntegral n) (fromIntegral n + 1)
81{-# INLINE sourceFromList #-}
82sourceFromList :: (Monad m, S.IsStream t) => Int -> t m Int
83sourceFromList n = S.fromList [n..n+value]
85{-# INLINE sourceFromListM #-}
86sourceFromListM :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
87sourceFromListM n = S.fromListM (Prelude.fmap return [n..n+value])
89{-# INLINE sourceFromIndices #-}
90sourceFromIndices :: (Monad m, S.IsStream t) => Int -> t m Int
91sourceFromIndices n = S.take value $ S.fromIndices (+ n)
93{-# INLINE sourceFromIndicesM #-}
94sourceFromIndicesM :: (S.MonadAsync m, S.IsStream t) => Int -> t m Int
95sourceFromIndicesM n = S.take value $ S.fromIndicesM (Prelude.fmap return (+ n))
97{-# INLINE sourceFromFoldable #-}
98sourceFromFoldable :: S.IsStream t => Int -> t m Int
99sourceFromFoldable n = S.fromFoldable [n..n+value]
101{-# INLINE sourceFromFoldableM #-}
102sourceFromFoldableM :: (S.IsStream t, S.MonadAsync m) => Int -> t m Int
103sourceFromFoldableM n = S.fromFoldableM (Prelude.fmap return [n..n+value])
105{-# INLINE sourceFoldMapWith #-}
106sourceFoldMapWith :: (S.IsStream t, S.Semigroup (t m Int))
107 => Int -> t m Int
108sourceFoldMapWith n = S.foldMapWith (S.<>) S.yield [n..n+value]
110{-# INLINE sourceFoldMapWithM #-}
111sourceFoldMapWithM :: (S.IsStream t, Monad m, S.Semigroup (t m Int))
112 => Int -> t m Int
113sourceFoldMapWithM n = S.foldMapWith (S.<>) (S.yieldM . return) [n..n+value]
115{-# INLINE sourceFoldMapM #-}
116sourceFoldMapM :: (S.IsStream t, Monad m, P.Monoid (t m Int))
117 => Int -> t m Int
118sourceFoldMapM n = F.foldMap (S.yieldM . return) [n..n+value]
120{-# INLINE sourceUnfoldr #-}
121sourceUnfoldr :: (Monad m, S.IsStream t) => Int -> t m Int
122sourceUnfoldr n = S.unfoldr step n
123 where
124 step cnt =
125 if cnt > n + value
126 then Nothing
127 else Just (cnt, cnt + 1)
129{-# INLINE sourceUnfoldrN #-}
130sourceUnfoldrN :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
131sourceUnfoldrN upto start = S.unfoldr step start
132 where
133 step cnt =
134 if cnt > start + upto
135 then Nothing
136 else Just (cnt, cnt + 1)
138{-# INLINE sourceUnfoldrM #-}
139sourceUnfoldrM :: (S.IsStream t, S.MonadAsync m) => Int -> t m Int
140sourceUnfoldrM n = S.unfoldrM step n
141 where
142 step cnt =
143 if cnt > n + value
144 then return Nothing
145 else return (Just (cnt, cnt + 1))
147{-# INLINE sourceUnfoldrMN #-}
148sourceUnfoldrMN :: (S.IsStream t, S.MonadAsync m) => Int -> Int -> t m Int
149sourceUnfoldrMN upto start = S.unfoldrM step start
150 where
151 step cnt =
152 if cnt > start + upto
153 then return Nothing
154 else return (Just (cnt, cnt + 1))
156{-# INLINE sourceUnfoldrMAction #-}
157sourceUnfoldrMAction :: (S.IsStream t, S.MonadAsync m) => Int -> t m (m Int)
158sourceUnfoldrMAction n = S.serially $ S.unfoldrM step n
159 where
160 step cnt =
161 if cnt > n + value
162 then return Nothing
163 else return (Just (return cnt, cnt + 1))
165-------------------------------------------------------------------------------
166-- Pure stream generation
167-------------------------------------------------------------------------------
169{-# INLINE sourceIsList #-}
170sourceIsList :: Int -> S.SerialT Identity Int
171sourceIsList n = GHC.fromList [n..n+value]
173{-# INLINE sourceIsString #-}
174sourceIsString :: Int -> S.SerialT Identity P.Char
175sourceIsString n = GHC.fromString (P.replicate (n + value) 'a')
177-------------------------------------------------------------------------------
178-- Elimination
179-------------------------------------------------------------------------------
181{-# INLINE runStream #-}
182runStream :: Monad m => Stream m a -> m ()
183runStream = S.drain
185{-# INLINE toList #-}
186toList :: Monad m => Stream m Int -> m [Int]
188{-# INLINE head #-}
189{-# INLINE last #-}
190{-# INLINE maximum #-}
191{-# INLINE minimum #-}
192{-# INLINE find #-}
193{-# INLINE findIndex #-}
194{-# INLINE elemIndex #-}
195{-# INLINE foldl1'Reduce #-}
196head, last, minimum, maximum, find, findIndex, elemIndex, foldl1'Reduce
197 :: Monad m => Stream m Int -> m (Maybe Int)
199{-# INLINE minimumBy #-}
200{-# INLINE maximumBy #-}
201minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
203{-# INLINE foldl'Reduce #-}
204{-# INLINE foldl'ReduceMap #-}
205{-# INLINE foldlM'Reduce #-}
206{-# INLINE foldrMReduce #-}
207{-# INLINE length #-}
208{-# INLINE sum #-}
209{-# INLINE product #-}
210foldl'Reduce, foldl'ReduceMap, foldlM'Reduce, foldrMReduce, length, sum, product
211 :: Monad m
212 => Stream m Int -> m Int
214{-# INLINE foldl'Build #-}
215{-# INLINE foldlM'Build #-}
216{-# INLINE foldrMBuild #-}
217foldrMBuild, foldl'Build, foldlM'Build
218 :: Monad m
219 => Stream m Int -> m [Int]
221{-# INLINE all #-}
222{-# INLINE any #-}
223{-# INLINE and #-}
224{-# INLINE or #-}
225{-# INLINE null #-}
226{-# INLINE elem #-}
227{-# INLINE notElem #-}
228null, elem, notElem, all, any, and, or :: Monad m => Stream m Int -> m Bool
230{-# INLINE toNull #-}
231toNull :: Monad m => (t m a -> S.SerialT m a) -> t m a -> m ()
232toNull t = runStream . t
234{-# INLINE uncons #-}
235uncons :: Monad m => Stream m Int -> m ()
236uncons s = do
237 r <- S.uncons s
238 case r of
239 Nothing -> return ()
240 Just (_, t) -> uncons t
242{-# INLINE init #-}
243init :: Monad m => Stream m a -> m ()
244init s = S.init s >>= Prelude.mapM_ S.drain
246{-# INLINE tail #-}
247tail :: Monad m => Stream m a -> m ()
248tail s = S.tail s >>= Prelude.mapM_ tail
250{-# INLINE nullHeadTail #-}
251nullHeadTail :: Monad m => Stream m Int -> m ()
252nullHeadTail s = do
253 r <- S.null s
254 when (not r) $ do
255 _ <- S.head s
256 S.tail s >>= Prelude.mapM_ nullHeadTail
258{-# INLINE mapM_ #-}
259mapM_ :: Monad m => Stream m Int -> m ()
260mapM_ = S.mapM_ (\_ -> return ())
262toList = S.toList
264{-
265{-# INLINE toRevList #-}
266toRevList :: Monad m => Stream m Int -> m [Int]
267toRevList = S.toRevList
268-}
270foldrMBuild = S.foldrM (\x xs -> xs >>= return . (x :)) (return [])
271foldl'Build = S.foldl' (flip (:)) []
272foldlM'Build = S.foldlM' (\xs x -> return $ x : xs) []
274foldrMReduce = S.foldrM (\x xs -> xs >>= return . (x +)) (return 0)
275foldl'Reduce = S.foldl' (+) 0
276foldl'ReduceMap = P.fmap (+1) . S.foldl' (+) 0
277foldl1'Reduce = S.foldl1' (+)
278foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
280last = S.last
281null = S.null
282head = S.head
283elem = S.elem maxValue
284notElem = S.notElem maxValue
285length = S.length
286all = S.all (<= maxValue)
287any = S.any (> maxValue)
288and = S.and . S.map (<= maxValue)
289or = S.or . S.map (> maxValue)
290find = S.find (== maxValue)
291findIndex = S.findIndex (== maxValue)
292elemIndex = S.elemIndex maxValue
293maximum = S.maximum
294minimum = S.minimum
295sum = S.sum
296product = S.product
297minimumBy = S.minimumBy compare
298maximumBy = S.maximumBy compare
300-------------------------------------------------------------------------------
301-- Transformation
302-------------------------------------------------------------------------------
304{-# INLINE transform #-}
305transform :: Monad m => Stream m a -> m ()
306transform = runStream
308{-# INLINE composeN #-}
309composeN
310 :: MonadIO m
311 => Int -> (Stream m Int -> Stream m Int) -> Stream m Int -> m ()
312composeN n f =
313 case n of
314 1 -> transform . f
315 2 -> transform . f . f
316 3 -> transform . f . f . f
317 4 -> transform . f . f . f . f
318 _ -> undefined
320-- polymorphic stream version of composeN
321{-# INLINE composeN' #-}
322composeN'
323 :: (S.IsStream t, Monad m)
324 => Int -> (t m Int -> Stream m Int) -> t m Int -> m ()
325composeN' n f =
326 case n of
327 1 -> transform . f
328 2 -> transform . f . S.adapt . f
329 3 -> transform . f . S.adapt . f . S.adapt . f
330 4 -> transform . f . S.adapt . f . S.adapt . f . S.adapt . f
331 _ -> undefined
333{-# INLINE scan #-}
334{-# INLINE scanl1' #-}
335{-# INLINE map #-}
336{-# INLINE fmap #-}
337{-# INLINE mapMaybe #-}
338{-# INLINE filterEven #-}
339{-# INLINE filterAllOut #-}
340{-# INLINE filterAllIn #-}
341{-# INLINE takeOne #-}
342{-# INLINE takeAll #-}
343{-# INLINE takeWhileTrue #-}
344{-# INLINE takeWhileMTrue #-}
345{-# INLINE dropOne #-}
346{-# INLINE dropAll #-}
347{-# INLINE dropWhileTrue #-}
348{-# INLINE dropWhileMTrue #-}
349{-# INLINE dropWhileFalse #-}
350{-# INLINE findIndices #-}
351{-# INLINE elemIndices #-}
352{-# INLINE insertBy #-}
353{-# INLINE deleteBy #-}
354{-# INLINE reverse #-}
355{-# INLINE reverse' #-}
356{-# INLINE foldrS #-}
357{-# INLINE foldrSMap #-}
358{-# INLINE foldrT #-}
359{-# INLINE foldrTMap #-}
360scan, scanl1', map, fmap, mapMaybe, filterEven, filterAllOut,
361 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropOne,
362 dropAll, dropWhileTrue, dropWhileMTrue, dropWhileFalse,
363 findIndices, elemIndices, insertBy, deleteBy, reverse, reverse',
364 foldrS, foldrSMap, foldrT, foldrTMap
365 :: MonadIO m
366 => Int -> Stream m Int -> m ()
368{-# INLINE mapMaybeM #-}
369{-# INLINE intersperse #-}
370mapMaybeM, intersperse :: S.MonadAsync m => Int -> Stream m Int -> m ()
372{-# INLINE mapM #-}
373{-# INLINE map' #-}
374{-# INLINE fmap' #-}
375mapM, map' :: (S.IsStream t, S.MonadAsync m)
376 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
378fmap' :: (S.IsStream t, S.MonadAsync m, P.Functor (t m))
379 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
381{-# INLINE sequence #-}
382sequence :: (S.IsStream t, S.MonadAsync m)
383 => (t m Int -> S.SerialT m Int) -> t m (m Int) -> m ()
385scan n = composeN n $ S.scanl' (+) 0
386scanl1' n = composeN n $ S.scanl1' (+)
387fmap n = composeN n $ Prelude.fmap (+1)
388fmap' t n = composeN' n $ t . Prelude.fmap (+1)
389map n = composeN n $ S.map (+1)
390map' t n = composeN' n $ t . S.map (+1)
391mapM t n = composeN' n $ t . S.mapM return
393-- Temporarily commented these ops as they depend on the hidden
394-- Pipe module.
395{-
396{-# INLINE transformMapM #-}
397{-# INLINE transformComposeMapM #-}
398{-# INLINE transformTeeMapM #-}
399{-# INLINE transformZipMapM #-}
401transformMapM, transformComposeMapM, transformTeeMapM,
402 transformZipMapM :: (S.IsStream t, S.MonadAsync m)
403 => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
405transformMapM t n = composeN' n $ t . S.transform (Pipe.mapM return)
406transformComposeMapM t n = composeN' n $ t . S.transform
407 (Pipe.mapM (\x -> return (x + 1))
408 `Pipe.compose` Pipe.mapM (\x -> return (x + 2)))
409transformTeeMapM t n = composeN' n $ t . S.transform
410 (Pipe.mapM (\x -> return (x + 1))
411 `Pipe.tee` Pipe.mapM (\x -> return (x + 2)))
412transformZipMapM t n = composeN' n $ t . S.transform
413 (Pipe.zipWith (+) (Pipe.mapM (\x -> return (x + 1)))
414 (Pipe.mapM (\x -> return (x + 2))))
415-}
417mapMaybe n = composeN n $ S.mapMaybe
418 (\x -> if Prelude.odd x then Nothing else Just x)
419mapMaybeM n = composeN n $ S.mapMaybeM
420 (\x -> if Prelude.odd x then return Nothing else return $ Just x)
421sequence t = transform . t . S.sequence
422filterEven n = composeN n $ S.filter even
423filterAllOut n = composeN n $ S.filter (> maxValue)
424filterAllIn n = composeN n $ S.filter (<= maxValue)
425takeOne n = composeN n $ S.take 1
426takeAll n = composeN n $ S.take maxValue
427takeWhileTrue n = composeN n $ S.takeWhile (<= maxValue)
428takeWhileMTrue n = composeN n $ S.takeWhileM (return . (<= maxValue))
429dropOne n = composeN n $ S.drop 1
430dropAll n = composeN n $ S.drop maxValue
431dropWhileTrue n = composeN n $ S.dropWhile (<= maxValue)
432dropWhileMTrue n = composeN n $ S.dropWhileM (return . (<= maxValue))
433dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
434findIndices n = composeN n $ S.findIndices (== maxValue)
435elemIndices n = composeN n $ S.elemIndices maxValue
436intersperse n = composeN n $ S.intersperse maxValue
437insertBy n = composeN n $ S.insertBy compare maxValue
438deleteBy n = composeN n $ S.deleteBy (>=) maxValue
439reverse n = composeN n $ S.reverse
440reverse' n = composeN n $ S.reverse'
441foldrS n = composeN n $ S.foldrS S.cons S.nil
442foldrSMap n = composeN n $ S.foldrS (\x xs -> x + 1 `S.cons` xs) S.nil
443foldrT n = composeN n $ S.foldrT S.cons S.nil
444foldrTMap n = composeN n $ S.foldrT (\x xs -> x + 1 `S.cons` xs) S.nil
446-------------------------------------------------------------------------------
447-- Iteration
448-------------------------------------------------------------------------------
450iterStreamLen, maxIters :: Int
451iterStreamLen = 10
452maxIters = 10000
454{-# INLINE iterateSource #-}
455iterateSource
456 :: S.MonadAsync m
457 => (Stream m Int -> Stream m Int) -> Int -> Int -> Stream m Int
458iterateSource g i n = f i (sourceUnfoldrMN iterStreamLen n)
459 where
460 f (0 :: Int) m = g m
461 f x m = g (f (x P.- 1) m)
463{-# INLINE iterateMapM #-}
464{-# INLINE iterateScan #-}
465{-# INLINE iterateScanl1 #-}
466{-# INLINE iterateFilterEven #-}
467{-# INLINE iterateTakeAll #-}
468{-# INLINE iterateDropOne #-}
469{-# INLINE iterateDropWhileFalse #-}
470{-# INLINE iterateDropWhileTrue #-}
471iterateMapM, iterateScan, iterateScanl1, iterateFilterEven, iterateTakeAll,
472 iterateDropOne, iterateDropWhileFalse, iterateDropWhileTrue
473 :: S.MonadAsync m
474 => Int -> Stream m Int
476-- this is quadratic
477iterateScan = iterateSource (S.scanl' (+) 0) (maxIters `div` 10)
478-- so is this
479iterateScanl1 = iterateSource (S.scanl1' (+)) (maxIters `div` 10)
481iterateMapM = iterateSource (S.mapM return) maxIters
482iterateFilterEven = iterateSource (S.filter even) maxIters
483iterateTakeAll = iterateSource (S.take maxValue) maxIters
484iterateDropOne = iterateSource (S.drop 1) maxIters
485iterateDropWhileFalse = iterateSource (S.dropWhile (> maxValue)) maxIters
486iterateDropWhileTrue = iterateSource (S.dropWhile (<= maxValue)) maxIters
488-------------------------------------------------------------------------------
489-- Zipping and concat
490-------------------------------------------------------------------------------
492{-# INLINE zip #-}
493{-# INLINE zipM #-}
494{-# INLINE mergeBy #-}
495zip, zipM, mergeBy :: Monad m => Stream m Int -> m ()
497zip src = do
498 r <- S.tail src
499 let src1 = fromJust r
500 transform (S.zipWith (,) src src1)
501zipM src = do
502 r <- S.tail src
503 let src1 = fromJust r
504 transform (S.zipWithM (curry return) src src1)
506mergeBy src = do
507 r <- S.tail src
508 let src1 = fromJust r
509 transform (S.mergeBy P.compare src src1)
511{-# INLINE isPrefixOf #-}
512{-# INLINE isSubsequenceOf #-}
513isPrefixOf, isSubsequenceOf :: Monad m => Stream m Int -> m Bool
515isPrefixOf src = S.isPrefixOf src src
516isSubsequenceOf src = S.isSubsequenceOf src src
518{-# INLINE stripPrefix #-}
519stripPrefix :: Monad m => Stream m Int -> m ()
520stripPrefix src = do
521 _ <- S.stripPrefix src src
522 return ()
524{-# INLINE zipAsync #-}
525{-# INLINE zipAsyncM #-}
526{-# INLINE zipAsyncAp #-}
527zipAsync, zipAsyncAp, zipAsyncM :: S.MonadAsync m => Stream m Int -> m ()
529zipAsync src = do
530 r <- S.tail src
531 let src1 = fromJust r
532 transform (S.zipAsyncWith (,) src src1)
534zipAsyncM src = do
535 r <- S.tail src
536 let src1 = fromJust r
537 transform (S.zipAsyncWithM (curry return) src src1)
539zipAsyncAp src = do
540 r <- S.tail src
541 let src1 = fromJust r
542 transform (S.zipAsyncly $ (,) <$> S.serially src
543 <*> S.serially src1)
545{-# INLINE eqBy #-}
546eqBy :: (Monad m, P.Eq a) => Stream m a -> m P.Bool
547eqBy src = S.eqBy (==) src src
549{-# INLINE cmpBy #-}
550cmpBy :: (Monad m, P.Ord a) => Stream m a -> m P.Ordering
551cmpBy src = S.cmpBy P.compare src src
553-- The worst case for concatMap, concat a 1 element stream n times.
554{-# INLINE concatMap #-}
555concatMap :: S.MonadAsync m => Int -> Stream m Int
556concatMap n = S.concatMap (\_ -> sourceUnfoldrMN 1 n)
557 (sourceUnfoldrMN value n)
559{-# INLINE concatMapPure1xN #-}
560concatMapPure1xN :: S.MonadAsync m => Int -> Stream m Int
561concatMapPure1xN n = S.concatMap (\_ -> sourceUnfoldrN 1 n)
562 (sourceUnfoldrN value n)
564-- We use a (sqrt n) element stream as source and then generate and concat a
565-- (sqrt n) element stream for each element of the source to produce an n
566-- element stream.
567{-# INLINE concatMapNxN #-}
568concatMapNxN :: S.MonadAsync m => Int -> Stream m Int
569concatMapNxN n = S.concatMap (\_ -> sourceUnfoldrMN value2 n)
570 (sourceUnfoldrMN value2 n)
572{-# INLINE concatMapRepl4xN #-}
573concatMapRepl4xN :: S.MonadAsync m => Int -> Stream m Int
574concatMapRepl4xN n = S.concatMap (S.replicate 4)
575 (sourceUnfoldrMN (value `div` 4) n)
577-------------------------------------------------------------------------------
578-- Mixed Composition
579-------------------------------------------------------------------------------
581{-# INLINE scanMap #-}
582{-# INLINE dropMap #-}
583{-# INLINE dropScan #-}
584{-# INLINE takeDrop #-}
585{-# INLINE takeScan #-}
586{-# INLINE takeMap #-}
587{-# INLINE filterDrop #-}
588{-# INLINE filterTake #-}
589{-# INLINE filterScan #-}
590{-# INLINE filterScanl1 #-}
591{-# INLINE filterMap #-}
592scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
593 filterTake, filterScan, filterScanl1, filterMap
594 :: MonadIO m => Int -> Stream m Int -> m ()
596scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
597dropMap n = composeN n $ S.map (subtract 1) . S.drop 1
598dropScan n = composeN n $ S.scanl' (+) 0 . S.drop 1
599takeDrop n = composeN n $ S.drop 1 . S.take maxValue
600takeScan n = composeN n $ S.scanl' (+) 0 . S.take maxValue
601takeMap n = composeN n $ S.map (subtract 1) . S.take maxValue
602filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
603filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
604filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
605filterScanl1 n = composeN n $ S.scanl1' (+) . S.filter (<= maxBound)
606filterMap n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
608data Pair a b = Pair !a !b deriving (Generic, NFData)
610{-# INLINE sumProductFold #-}
611sumProductFold :: Monad m => Stream m Int -> m (Int, Int)
612sumProductFold = S.foldl' (\(s,p) x -> (s + x, p P.* x)) (0,1)
614{-# INLINE sumProductScan #-}
615sumProductScan :: Monad m => Stream m Int -> m (Pair Int Int)
616sumProductScan = S.foldl' (\(Pair _ p) (s0,x) -> Pair s0 (p P.* x)) (Pair 0 1)
617 . S.scanl' (\(s,_) x -> (s + x,x)) (0,0)
619-------------------------------------------------------------------------------
620-- Pure stream operations
621-------------------------------------------------------------------------------
623{-# INLINE eqInstance #-}
624eqInstance :: Stream Identity Int -> Bool
625eqInstance src = src == src
627{-# INLINE eqInstanceNotEq #-}
628eqInstanceNotEq :: Stream Identity Int -> Bool
629eqInstanceNotEq src = src P./= src
631{-# INLINE ordInstance #-}
632ordInstance :: Stream Identity Int -> Bool
633ordInstance src = src P.< src
635{-# INLINE ordInstanceMin #-}
636ordInstanceMin :: Stream Identity Int -> Stream Identity Int
637ordInstanceMin src = P.min src src
639{-# INLINE showInstance #-}
640showInstance :: Stream Identity Int -> P.String
641showInstance src = P.show src
643{-# INLINE showInstanceList #-}
644showInstanceList :: [Int] -> P.String
645showInstanceList src = P.show src
647{-# INLINE readInstance #-}
648readInstance :: P.String -> Stream Identity Int
649readInstance str =
650 let r = P.reads str
651 in case r of
652 [(x,"")] -> x
653 _ -> P.error "readInstance: no parse"
655{-# INLINE readInstanceList #-}
656readInstanceList :: P.String -> [Int]
657readInstanceList str =
658 let r = P.reads str
659 in case r of
660 [(x,"")] -> x
661 _ -> P.error "readInstance: no parse"
663{-# INLINE pureFoldl' #-}
664pureFoldl' :: Stream Identity Int -> Int
665pureFoldl' = runIdentity . S.foldl' (+) 0
667{-# INLINE foldableFoldl' #-}
668foldableFoldl' :: Stream Identity Int -> Int
669foldableFoldl' = F.foldl' (+) 0
671{-# INLINE foldableSum #-}
672foldableSum :: Stream Identity Int -> Int
673foldableSum = P.sum
675{-# INLINE traversableMapM #-}
676traversableMapM :: Stream Identity Int -> IO (Stream Identity Int)
677traversableMapM = P.mapM return