on master help sign in
Add transformation/filtering/mixed composition benchmarks
819786eHarendra Kumar
benchmark/Chart.hs+36−19
@@ -85,34 +85,51 @@ ignoringErr a = catch a (\(ErrorCall err :: ErrorCall) ->
85
85
86makeLinearGraphs :: Config -> String -> IO ()
86makeLinearGraphs :: Config -> String -> IO ()
87makeLinearGraphs cfg inputFile = do
87makeLinearGraphs cfg inputFile = do
88− ignoringErr $ graph inputFile "operations" $ cfg
88+ ignoringErr $ graph inputFile "generation" $ cfg
89− { title = Just "Streamly operations"
89+ { title = Just "Generation"
90− , classifyBenchmark = \b ->
90+ , classifyBenchmark =
91− if not ("serially/" `isPrefixOf` b)
91+ fmap ("Streamly",) . stripPrefix "serially/generation/"
92− || "/generation" `isInfixOf` b
93− || "/compose" `isInfixOf` b
94− || "/concat" `isSuffixOf` b
95− then Nothing
96− else Just ("Streamly", last $ splitOn "/" b)
97 }
92 }
98
93
99− ignoringErr $ graph inputFile "generation" $ cfg
94+ ignoringErr $ graph inputFile "elimination" $ cfg
100− { title = Just "Stream generation"
95+ { title = Just "Elimination"
96+ , classifyBenchmark =
97+ fmap ("Streamly",) . stripPrefix "serially/elimination/"
98+ }
99+
100+ ignoringErr $ graph inputFile "transformation-zip" $ cfg
101+ { title = Just "Transformation & Zip"
101 , classifyBenchmark = \b ->
102 , classifyBenchmark = \b ->
103+ if "serially/transformation/" `isPrefixOf` b
102− if "serially/generation" `isPrefixOf` b
104+ || "serially/zip" `isPrefixOf` b
103 then Just ("Streamly", last $ splitOn "/" b)
105 then Just ("Streamly", last $ splitOn "/" b)
104 else Nothing
106 else Nothing
105 }
107 }
106
108
107− ignoringErr $ graph inputFile "composition" $ cfg
109+ ignoringErr $ graph inputFile "filtering" $ cfg
108− { title = Just "Streamly composition performance"
110+ { title = Just "Filtering"
111+ , classifyBenchmark =
112+ fmap ("Streamly",) . stripPrefix "serially/filtering/"
113+ }
114+
115+ ignoringErr $ graph inputFile "composed-transformation" $ cfg
116+ { title = Just "Composed Transformation"
117+ , classifyBenchmark =
118+ fmap ("Streamly",) . stripPrefix "serially/transformationN/"
119+ }
120+
121+ ignoringErr $ graph inputFile "composed-filtering"
122+ $ cfg
123+ { title = Just "Composed Filtering"
124+ , classifyBenchmark =
109− , classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose/"
125+ fmap ("Streamly",) . stripPrefix "serially/filteringN/"
110 }
126 }
111
127
112− ignoringErr $ graph inputFile "composition-scaling"
128+ ignoringErr $ graph inputFile "composed-mixed"
113 $ cfg
129 $ cfg
114− { title = Just "Streamly composition scaling"
130+ { title = Just "Composed Mixed"
131+ , classifyBenchmark =
115− , classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose-"
132+ fmap ("Streamly",) . stripPrefix "serially/composed/"
116 }
133 }
117
134
118------------------------------------------------------------------------------
135------------------------------------------------------------------------------
@@ -121,7 +138,7 @@ makeLinearGraphs cfg inputFile = do
121
138
122makeNestedGraphs :: Config -> String -> IO ()
139makeNestedGraphs :: Config -> String -> IO ()
123makeNestedGraphs cfg inputFile =
140makeNestedGraphs cfg inputFile =
124− ignoringErr $ graph inputFile "nested-serial-diff" $ cfg
141+ ignoringErr $ graph inputFile "nested-serial" $ cfg
125 { title = Just "Nested serial"
142 { title = Just "Nested serial"
126 , classifyBenchmark = \b ->
143 , classifyBenchmark = \b ->
127 let ls = splitOn "/" b
144 let ls = splitOn "/" b
benchmark/Linear.hs+53−30
@@ -84,43 +84,66 @@ main =
84 , benchIO "product" Ops.product
84 , benchIO "product" Ops.product
85 ]
85 ]
86 , bgroup "transformation"
86 , bgroup "transformation"
87− [ benchIO "scan" Ops.scan
87+ [ benchIO "scan" (Ops.scan 1)
88− , benchIO "map" Ops.map
88+ , benchIO "map" (Ops.map 1)
89− , benchIO "fmap" Ops.fmap
89+ , benchIO "fmap" (Ops.fmap 1)
90− , benchIO "mapM" (Ops.mapM serially)
90+ , benchIO "mapM" (Ops.mapM serially 1)
91− , benchIO "mapMaybe" Ops.mapMaybe
91+ , benchIO "mapMaybe" (Ops.mapMaybe 1)
92− , benchIO "mapMaybeM" Ops.mapMaybeM
92+ , benchIO "mapMaybeM" (Ops.mapMaybeM 1)
93 , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
93 , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
94 Ops.sequence serially (Ops.sourceUnfoldrMAction n)
94 Ops.sequence serially (Ops.sourceUnfoldrMAction n)
95− , benchIO "findIndices" Ops.findIndices
95+ , benchIO "findIndices" (Ops.findIndices 1)
96+ , benchIO "elemIndices" (Ops.elemIndices 1)
97+ -- , benchIO "concat" Ops.concat
98+ ]
99+ , bgroup "transformationN"
100+ [ benchIO "scan" (Ops.scan 4)
101+ , benchIO "map" (Ops.map 4)
102+ , benchIO "fmap" (Ops.fmap 4)
103+ , benchIO "mapM" (Ops.mapM serially 4)
104+ , benchIO "mapMaybe" (Ops.mapMaybe 4)
105+ , benchIO "mapMaybeM" (Ops.mapMaybeM 4)
106+ -- , bench "sequence" $ nfIO $ randomRIO (1,1000) >>= \n ->
107+ -- Ops.sequence serially (Ops.sourceUnfoldrMAction n)
108+ , benchIO "findIndices" (Ops.findIndices 4)
96− , benchIO "elemIndices" Ops.elemIndices
109+ , benchIO "elemIndices" (Ops.elemIndices 4)
97 -- , benchIO "concat" Ops.concat
110 -- , benchIO "concat" Ops.concat
98 ]
111 ]
99 , bgroup "filtering"
112 , bgroup "filtering"
100− [ benchIO "filter-even" Ops.filterEven
113+ [ benchIO "filter-even" (Ops.filterEven 1)
101− , benchIO "filter-all-out" Ops.filterAllOut
114+ , benchIO "filter-all-out" (Ops.filterAllOut 1)
102− , benchIO "filter-all-in" Ops.filterAllIn
115+ , benchIO "filter-all-in" (Ops.filterAllIn 1)
103− , benchIO "take-all" Ops.takeAll
116+ , benchIO "take-all" (Ops.takeAll 1)
104− , benchIO "takeWhile-true" Ops.takeWhileTrue
117+ , benchIO "takeWhile-true" (Ops.takeWhileTrue 1)
105− , benchIO "takeWhileM-true" Ops.takeWhileMTrue
118+ , benchIO "takeWhileM-true" (Ops.takeWhileMTrue 1)
106− , benchIO "drop-all" Ops.dropAll
119+ , benchIO "drop-all" (Ops.dropAll 1)
107− , benchIO "dropWhile-true" Ops.dropWhileTrue
120+ , benchIO "dropWhile-true" (Ops.dropWhileTrue 1)
121+ , benchIO "dropWhileM-true" (Ops.dropWhileMTrue 1)
122+ ]
123+ , bgroup "filteringN"
124+ [ benchIO "filter-even" (Ops.filterEven 4)
125+ , benchIO "filter-all-out" (Ops.filterAllOut 4)
126+ , benchIO "filter-all-in" (Ops.filterAllIn 4)
127+ , benchIO "take-all" (Ops.takeAll 4)
128+ , benchIO "takeWhile-true" (Ops.takeWhileTrue 4)
129+ , benchIO "takeWhileM-true" (Ops.takeWhileMTrue 4)
130+ , benchIO "drop-all" (Ops.dropAll 4)
131+ , benchIO "dropWhile-true" (Ops.dropWhileTrue 4)
108− , benchIO "dropWhileM-true" Ops.dropWhileMTrue
132+ , benchIO "dropWhileM-true" (Ops.dropWhileMTrue 4)
109 ]
133 ]
110 , benchIO "zip" Ops.zip
134 , benchIO "zip" Ops.zip
111 , benchIO "zipM" Ops.zipM
135 , benchIO "zipM" Ops.zipM
112− , bgroup "compose"
136+ , bgroup "composed"
113− [ benchIO "mapM" Ops.composeMapM
137+ [ benchIO "scan-map" (Ops.scanMap 4)
114− , benchIO "map-with-all-in-filter" Ops.composeMapAllInFilter
138+ , benchIO "drop-map" (Ops.dropMap 4)
115− , benchIO "all-in-filters" Ops.composeAllInFilters
139+ , benchIO "drop-scan" (Ops.dropScan 4)
116− , benchIO "all-out-filters" Ops.composeAllOutFilters
140+ , benchIO "take-drop" (Ops.takeDrop 4)
117− ]
141+ , benchIO "take-scan" (Ops.takeScan 4)
118− -- Scaling with same operation in sequence
142+ , benchIO "take-map" (Ops.takeMap 4)
119− , bgroup "compose-scaling"
143+ , benchIO "filter-drop" (Ops.filterDrop 4)
120− [ benchIO "1" $ Ops.composeScaling 1
144+ , benchIO "filter-take" (Ops.filterTake 4)
121− , benchIO "2" $ Ops.composeScaling 2
145+ , benchIO "filter-scan" (Ops.filterScan 4)
122− , benchIO "3" $ Ops.composeScaling 3
123− , benchIO "4" $ Ops.composeScaling 4
146+ , benchIO "filter-map" (Ops.filterMap 4)
124− ]
125 ]
147 ]
126 ]
148 ]
149+ ]
benchmark/LinearAsync.hs+4−4
@@ -46,7 +46,7 @@ main =
46 , benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
46 , benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
47 -- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
47 -- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
48 , benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
48 , benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
49− , benchIO "mapM" $ Ops.mapM asyncly
49+ , benchIO "mapM" $ Ops.mapM asyncly 1
50 , benchSrcIO asyncly "unfoldrM maxThreads 1"
50 , benchSrcIO asyncly "unfoldrM maxThreads 1"
51 (maxThreads 1 . Ops.sourceUnfoldrM)
51 (maxThreads 1 . Ops.sourceUnfoldrM)
52 , benchSrcIO asyncly "unfoldrM maxBuffer 1 (1000 ops)"
52 , benchSrcIO asyncly "unfoldrM maxBuffer 1 (1000 ops)"
@@ -59,7 +59,7 @@ main =
59 , benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
59 , benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
60 -- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
60 -- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
61 , benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
61 , benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
62− , benchIO "mapM" $ Ops.mapM wAsyncly
62+ , benchIO "mapM" $ Ops.mapM wAsyncly 1
63 ]
63 ]
64 -- unfoldr and fromFoldable are always serial and thereofore the same for
64 -- unfoldr and fromFoldable are always serial and thereofore the same for
65 -- all stream types.
65 -- all stream types.
@@ -69,7 +69,7 @@ main =
69 , benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
69 , benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
70 -- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
70 -- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
71 , benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
71 , benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
72− , benchIO "mapM" $ Ops.mapM aheadly
72+ , benchIO "mapM" $ Ops.mapM aheadly 1
73 , benchSrcIO aheadly "unfoldrM maxThreads 1"
73 , benchSrcIO aheadly "unfoldrM maxThreads 1"
74 (maxThreads 1 . Ops.sourceUnfoldrM)
74 (maxThreads 1 . Ops.sourceUnfoldrM)
75 , benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
75 , benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
@@ -84,7 +84,7 @@ main =
84 , benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
84 , benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
85 -- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
85 -- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
86 , benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
86 , benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
87− , benchIO "mapM" $ Ops.mapM parallely
87+ , benchIO "mapM" $ Ops.mapM parallely 1
88 -- Zip has only one parallel flavor
88 -- Zip has only one parallel flavor
89 , benchIO "zip" Ops.zipAsync
89 , benchIO "zip" Ops.zipAsync
90 , benchIO "zipM" Ops.zipAsyncM
90 , benchIO "zipM" Ops.zipAsyncM
benchmark/LinearOps.hs+79−57
@@ -14,7 +14,8 @@ import Control.Monad (when)
14import Data.Maybe (fromJust)
14import Data.Maybe (fromJust)
15import Prelude
15import Prelude
16 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (<=),
16 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=), (==), (<=),
17− subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry)
17+ subtract, undefined, Maybe(..), odd, Bool, not, (>>=), mapM_, curry,
18+ maxBound)
18
19
19import qualified Streamly as S
20import qualified Streamly as S
20import qualified Streamly.Prelude as S
21import qualified Streamly.Prelude as S
@@ -169,7 +170,10 @@ nullHeadTail s = do
169 _ <- S.head s
170 _ <- S.head s
170 S.tail s >>= Prelude.mapM_ nullHeadTail
171 S.tail s >>= Prelude.mapM_ nullHeadTail
171
172
173+{-# INLINE mapM_ #-}
174+mapM_ :: Monad m => Stream m Int -> m ()
172mapM_ = S.mapM_ (\_ -> return ())
175mapM_ = S.mapM_ (\_ -> return ())
176+
173toList = S.toList
177toList = S.toList
174foldr = S.foldr (:) []
178foldr = S.foldr (:) []
175foldr1 = S.foldr1 (+)
179foldr1 = S.foldr1 (+)
@@ -200,8 +204,32 @@ product = S.product
200transform :: Monad m => Stream m a -> m ()
204transform :: Monad m => Stream m a -> m ()
201transform = runStream
205transform = runStream
202
206
207+{-# INLINE composeN #-}
208+composeN
209+ :: Monad m
210+ => Int -> (Stream m Int -> Stream m Int) -> Stream m Int -> m ()
211+composeN n f =
212+ case n of
213+ 1 -> transform . f
214+ 2 -> transform . f . f
215+ 3 -> transform . f . f . f
216+ 4 -> transform . f . f . f . f
217+ _ -> undefined
218+
219+-- polymorphic stream version of composeN
220+{-# INLINE composeN' #-}
221+composeN'
222+ :: (S.IsStream t, Monad m)
223+ => Int -> (t m Int -> Stream m Int) -> t m Int -> m ()
224+composeN' n f =
225+ case n of
226+ 1 -> transform . f
227+ 2 -> transform . f . S.adapt . f
228+ 3 -> transform . f . S.adapt . f . S.adapt . f
229+ 4 -> transform . f . S.adapt . f . S.adapt . f . S.adapt . f
230+ _ -> undefined
231+
203{-# INLINE scan #-}
232{-# INLINE scan #-}
204−{-# INLINE mapM_ #-}
205{-# INLINE map #-}
233{-# INLINE map #-}
206{-# INLINE fmap #-}
234{-# INLINE fmap #-}
207{-# INLINE mapMaybe #-}
235{-# INLINE mapMaybe #-}
@@ -217,45 +245,45 @@ transform = runStream
217{-# INLINE dropWhileMTrue #-}
245{-# INLINE dropWhileMTrue #-}
218{-# INLINE findIndices #-}
246{-# INLINE findIndices #-}
219{-# INLINE elemIndices #-}
247{-# INLINE elemIndices #-}
220−scan, mapM_, map, fmap, mapMaybe, filterEven, filterAllOut,
248+scan, map, fmap, mapMaybe, filterEven, filterAllOut,
221 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropAll,
249 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropAll,
222 dropWhileTrue, dropWhileMTrue,
250 dropWhileTrue, dropWhileMTrue,
223 findIndices, elemIndices
251 findIndices, elemIndices
224 :: Monad m
252 :: Monad m
225− => Stream m Int -> m ()
253+ => Int -> Stream m Int -> m ()
226
254
227{-# INLINE mapMaybeM #-}
255{-# INLINE mapMaybeM #-}
228−mapMaybeM :: S.MonadAsync m => Stream m Int -> m ()
256+mapMaybeM :: S.MonadAsync m => Int -> Stream m Int -> m ()
229
257
230{-# INLINE mapM #-}
258{-# INLINE mapM #-}
231mapM :: (S.IsStream t, S.MonadAsync m)
259mapM :: (S.IsStream t, S.MonadAsync m)
232− => (t m Int -> S.SerialT m Int) -> t m Int -> m ()
260+ => (t m Int -> S.SerialT m Int) -> Int -> t m Int -> m ()
233
261
234{-# INLINE sequence #-}
262{-# INLINE sequence #-}
235sequence :: (S.IsStream t, S.MonadAsync m)
263sequence :: (S.IsStream t, S.MonadAsync m)
236 => (t m Int -> S.SerialT m Int) -> t m (m Int) -> m ()
264 => (t m Int -> S.SerialT m Int) -> t m (m Int) -> m ()
237
265
238−scan = transform . S.scanl' (+) 0
266+scan n = composeN n $ S.scanl' (+) 0
239−fmap = transform . Prelude.fmap (+1)
267+fmap n = composeN n $ Prelude.fmap (+1)
240−map = transform . S.map (+1)
268+map n = composeN n $ S.map (+1)
241−mapM t = transform . t . S.mapM return
269+mapM t n = composeN' n $ t . S.mapM return
242−mapMaybe = transform . S.mapMaybe
270+mapMaybe n = composeN n $ S.mapMaybe
243− (\x -> if Prelude.odd x then Nothing else Just ())
271+ (\x -> if Prelude.odd x then Nothing else Just x)
244−mapMaybeM = transform . S.mapMaybeM
272+mapMaybeM n = composeN n $ S.mapMaybeM
245− (\x -> if Prelude.odd x then return Nothing else return $ Just ())
273+ (\x -> if Prelude.odd x then return Nothing else return $ Just x)
246sequence t = transform . t . S.sequence
274sequence t = transform . t . S.sequence
247−filterEven = transform . S.filter even
275+filterEven n = composeN n $ S.filter even
248−filterAllOut = transform . S.filter (> maxValue)
276+filterAllOut n = composeN n $ S.filter (> maxValue)
249−filterAllIn = transform . S.filter (<= maxValue)
277+filterAllIn n = composeN n $ S.filter (<= maxValue)
250−takeOne = transform . S.take 1
278+takeOne n = composeN n $ S.take 1
251−takeAll = transform . S.take maxValue
279+takeAll n = composeN n $ S.take maxValue
252−takeWhileTrue = transform . S.takeWhile (<= maxValue)
280+takeWhileTrue n = composeN n $ S.takeWhile (<= maxValue)
253−takeWhileMTrue = transform . S.takeWhileM (return . (<= maxValue))
281+takeWhileMTrue n = composeN n $ S.takeWhileM (return . (<= maxValue))
254−dropAll = transform . S.drop maxValue
282+dropAll n = composeN n $ S.drop maxValue
255−dropWhileTrue = transform . S.dropWhile (<= maxValue)
283+dropWhileTrue n = composeN n $ S.dropWhile (<= maxValue)
256−dropWhileMTrue = transform . S.dropWhileM (return . (<= maxValue))
284+dropWhileMTrue n = composeN n $ S.dropWhileM (return . (<= maxValue))
257−findIndices = transform . S.findIndices (== maxValue)
285+findIndices n = composeN n $ S.findIndices (== maxValue)
258−elemIndices = transform . S.elemIndices maxValue
286+elemIndices n = composeN n $ S.elemIndices maxValue
259
287
260-------------------------------------------------------------------------------
288-------------------------------------------------------------------------------
261-- Zipping and concat
289-- Zipping and concat
@@ -289,36 +317,30 @@ zipAsyncM src = do
289concat _n = return ()
317concat _n = return ()
290
318
291-------------------------------------------------------------------------------
319-------------------------------------------------------------------------------
292−-- Composition
320+-- Mixed Composition
293-------------------------------------------------------------------------------
321-------------------------------------------------------------------------------
294
322
295−{-# INLINE compose #-}
323+{-# INLINE scanMap #-}
296−compose :: Monad m => (Stream m Int -> Stream m Int) -> Stream m Int -> m ()
324+{-# INLINE dropMap #-}
297−compose f = transform . f . f . f . f
325+{-# INLINE dropScan #-}
298−
326+{-# INLINE takeDrop #-}
299−{-# INLINE composeMapM #-}
327+{-# INLINE takeScan #-}
300−{-# INLINE composeAllInFilters #-}
328+{-# INLINE takeMap #-}
301−{-# INLINE composeAllOutFilters #-}
329+{-# INLINE filterDrop #-}
302−{-# INLINE composeMapAllInFilter #-}
330+{-# INLINE filterTake #-}
303−composeAllInFilters, composeAllOutFilters,
331+{-# INLINE filterScan #-}
304− composeMapAllInFilter
332+{-# INLINE filterMap #-}
305− :: Monad m
333+scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
334+ filterTake, filterScan, filterMap
306− => Stream m Int -> m ()
335+ :: Monad m => Int -> Stream m Int -> m ()
307−composeMapM :: S.MonadAsync m => Stream m Int -> m ()
336+
308−
337+scanMap n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
309−composeMapM = compose (S.mapM return)
338+dropMap n = composeN n $ S.map (subtract 1) . S.drop 1
310−composeAllInFilters = compose (S.filter (<= maxValue))
339+dropScan n = composeN n $ S.scanl' (+) 0 . S.drop 1
311−composeAllOutFilters = compose (S.filter (> maxValue))
340+takeDrop n = composeN n $ S.drop 1 . S.take maxValue
312−composeMapAllInFilter =
341+takeScan n = composeN n $ S.scanl' (+) 0 . S.take maxValue
313− compose (S.filter (<= maxValue) . Prelude.fmap (subtract 1))
342+takeMap n = composeN n $ S.map (subtract 1) . S.take maxValue
314−
343+filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
315−{-# INLINABLE composeScaling #-}
344+filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
316−composeScaling :: Monad m => Int -> Stream m Int -> m ()
345+filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
317−composeScaling m =
318− case m of
319− 1 -> transform . f
320− 2 -> transform . f . f
321− 3 -> transform . f . f . f
322− 4 -> transform . f . f . f . f
323− _ -> undefined
324− where f = S.filter (<= maxValue)
346+filterMap n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)