on master help sign in
push uncons/null/head/tail to StreamK
6530e76Harendra Kumar
benchmark/BaseStreams.hs+9−1
@@ -40,6 +40,11 @@ main = do
40 , benchIO "fromFoldable" D.toNull D.sourceFromFoldable
40 , benchIO "fromFoldable" D.toNull D.sourceFromFoldable
41 -- , benchIO "fromFoldableM" D.sourceFromFoldableM
41 -- , benchIO "fromFoldableM" D.sourceFromFoldableM
42 ]
42 ]
43+ , bgroup "elimination"
44+ [ benchIO "toNull" D.toNull D.sourceUnfoldrM
45+ , benchIO "uncons" D.uncons D.sourceUnfoldrM
46+ , benchIO "nullHeadTail" D.nullHeadTail D.sourceUnfoldrM
47+ ]
43 , bgroup "transformation"
48 , bgroup "transformation"
44 [ -- benchIO "scan" D.scan D.sourceUnfoldrM
49 [ -- benchIO "scan" D.scan D.sourceUnfoldrM
45 benchIO "map" D.map D.sourceUnfoldrM
50 benchIO "map" D.map D.sourceUnfoldrM
@@ -66,7 +71,10 @@ main = do
66 , benchIO "foldMapWithM" K.toNull K.sourceFoldMapWithM
71 , benchIO "foldMapWithM" K.toNull K.sourceFoldMapWithM
67 ]
72 ]
68 , bgroup "elimination"
73 , bgroup "elimination"
74+ [ benchIO "toNull" K.toNull K.sourceUnfoldrM
75+ , benchIO "uncons" K.uncons K.sourceUnfoldrM
76+ , benchIO "nullHeadTail" K.nullHeadTail K.sourceUnfoldrM
69− [ benchFold "toList" K.toList K.sourceUnfoldrM
77+ , benchFold "toList" K.toList K.sourceUnfoldrM
70 , benchFold "fold" K.foldl K.sourceUnfoldrM
78 , benchFold "fold" K.foldl K.sourceUnfoldrM
71 , benchFold "last" K.last K.sourceUnfoldrM
79 , benchFold "last" K.last K.sourceUnfoldrM
72 ]
80 ]
benchmark/Linear.hs+2
@@ -55,6 +55,8 @@ main = do
55 ]
55 ]
56 , bgroup "elimination"
56 , bgroup "elimination"
57 [ benchIO "toNull" $ Ops.toNull serially
57 [ benchIO "toNull" $ Ops.toNull serially
58+ , benchIO "uncons" Ops.uncons
59+ , benchIO "nullHeadTail" Ops.nullHeadTail
58 , benchIO "mapM_" Ops.mapM_
60 , benchIO "mapM_" Ops.mapM_
59 , benchIO "toList" Ops.toList
61 , benchIO "toList" Ops.toList
60 , benchIO "foldr" Ops.foldr
62 , benchIO "foldr" Ops.foldr
benchmark/LinearOps.hs+19−2
@@ -11,7 +11,7 @@ module LinearOps where
11
11
12import Prelude
12import Prelude
13 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
13 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
14− subtract, undefined, Maybe(..), odd, Bool)
14+ subtract, undefined, Maybe(..), odd, Bool, not)
15
15
16import qualified Streamly as S
16import qualified Streamly as S
17import qualified Streamly.Prelude as S
17import qualified Streamly.Prelude as S
@@ -24,6 +24,8 @@ maxValue = value + 1000
24-- Benchmark ops
24-- Benchmark ops
25-------------------------------------------------------------------------------
25-------------------------------------------------------------------------------
26
26
27+{-# INLINE uncons #-}
28+{-# INLINE nullHeadTail #-}
27{-# INLINE scan #-}
29{-# INLINE scan #-}
28{-# INLINE mapM_ #-}
30{-# INLINE mapM_ #-}
29{-# INLINE map #-}
31{-# INLINE map #-}
@@ -44,7 +46,7 @@ maxValue = value + 1000
44{-# INLINE composeAllInFilters #-}
46{-# INLINE composeAllInFilters #-}
45{-# INLINE composeAllOutFilters #-}
47{-# INLINE composeAllOutFilters #-}
46{-# INLINE composeMapAllInFilter #-}
48{-# INLINE composeMapAllInFilter #-}
47−scan, mapM_, map, fmap, mapMaybe, filterEven, filterAllOut,
49+uncons, nullHeadTail, scan, mapM_, map, fmap, mapMaybe, filterEven, filterAllOut,
48 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropAll,
50 filterAllIn, takeOne, takeAll, takeWhileTrue, takeWhileMTrue, dropAll,
49 dropWhileTrue, dropWhileMTrue, zip,
51 dropWhileTrue, dropWhileMTrue, zip,
50 concat, composeAllInFilters, composeAllOutFilters,
52 concat, composeAllInFilters, composeAllOutFilters,
@@ -163,6 +165,21 @@ runStream :: Monad m => Stream m a -> m ()
163runStream = S.runStream
165runStream = S.runStream
164
166
165toNull t = runStream . t
167toNull t = runStream . t
168+uncons s = do
169+ r <- S.uncons s
170+ case r of
171+ Nothing -> return ()
172+ Just (_, t) -> uncons t
173+nullHeadTail s = do
174+ r <- S.null s
175+ if not r
176+ then do
177+ _ <- S.head s
178+ t <- S.tail s
179+ case t of
180+ Nothing -> return ()
181+ Just x -> nullHeadTail x
182+ else return ()
166mapM_ = S.mapM_ (\_ -> return ())
183mapM_ = S.mapM_ (\_ -> return ())
167toList = S.toList
184toList = S.toList
168foldr = S.foldr (:) []
185foldr = S.foldr (:) []
benchmark/StreamDOps.hs+19−2
@@ -14,7 +14,7 @@ module StreamDOps where
14 -- subtract, undefined, Maybe(..))
14 -- subtract, undefined, Maybe(..))
15import Prelude
15import Prelude
16 (Monad, Int, (+), (.), return, (>), even, (<=),
16 (Monad, Int, (+), (.), return, (>), even, (<=),
17− Maybe(..))
17+ Maybe(..), not)
18
18
19import qualified Streamly.Streams.StreamD as S
19import qualified Streamly.Streams.StreamD as S
20
20
@@ -26,6 +26,8 @@ maxValue = value + 1000
26-- Benchmark ops
26-- Benchmark ops
27-------------------------------------------------------------------------------
27-------------------------------------------------------------------------------
28
28
29+{-# INLINE uncons #-}
30+{-# INLINE nullHeadTail #-}
29-- {-# INLINE scan #-}
31-- {-# INLINE scan #-}
30{-# INLINE map #-}
32{-# INLINE map #-}
31{-# INLINE filterEven #-}
33{-# INLINE filterEven #-}
@@ -43,7 +45,7 @@ maxValue = value + 1000
43{-# INLINE composeAllOutFilters #-}
45{-# INLINE composeAllOutFilters #-}
44{-# INLINE composeMapAllInFilter #-}
46{-# INLINE composeMapAllInFilter #-}
45-}
47-}
46−map, filterEven, filterAllOut,
48+uncons, nullHeadTail, map, filterEven, filterAllOut,
47 filterAllIn, takeOne, takeAll -- takeWhileTrue, dropAll, dropWhileTrue, zip,
49 filterAllIn, takeOne, takeAll -- takeWhileTrue, dropAll, dropWhileTrue, zip,
48 -- concat, composeAllInFilters, composeAllOutFilters,
50 -- concat, composeAllInFilters, composeAllOutFilters,
49 -- composeMapAllInFilter
51 -- composeMapAllInFilter
@@ -111,6 +113,21 @@ runStream :: Monad m => Stream m a -> m ()
111runStream = S.runStream
113runStream = S.runStream
112
114
113toNull = runStream
115toNull = runStream
116+uncons s = do
117+ r <- S.uncons s
118+ case r of
119+ Nothing -> return ()
120+ Just (_, t) -> uncons t
121+nullHeadTail s = do
122+ r <- S.null s
123+ if not r
124+ then do
125+ _ <- S.head s
126+ t <- S.tail s
127+ case t of
128+ Nothing -> return ()
129+ Just x -> nullHeadTail x
130+ else return ()
114toList = S.toList
131toList = S.toList
115foldl = S.foldl' (+) 0
132foldl = S.foldl' (+) 0
116last = S.last
133last = S.last
benchmark/StreamKOps.hs+22−4
@@ -11,7 +11,7 @@ module StreamKOps where
11
11
12import Prelude
12import Prelude
13 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
13 (Monad, Int, (+), ($), (.), return, fmap, even, (>), (<=),
14− subtract, undefined, Maybe(..))
14+ subtract, undefined, Maybe(..), not)
15
15
16import qualified Streamly.Streams.StreamK as S hiding (runStream)
16import qualified Streamly.Streams.StreamK as S hiding (runStream)
17-- import qualified Streamly.Streams.Serial as S
17-- import qualified Streamly.Streams.Serial as S
@@ -26,6 +26,9 @@ maxValue = value + 1000
26-- Benchmark ops
26-- Benchmark ops
27-------------------------------------------------------------------------------
27-------------------------------------------------------------------------------
28
28
29+{-# INLINE toNull #-}
30+{-# INLINE uncons #-}
31+{-# INLINE nullHeadTail #-}
29{-# INLINE scan #-}
32{-# INLINE scan #-}
30{-# INLINE map #-}
33{-# INLINE map #-}
31{-# INLINE filterEven #-}
34{-# INLINE filterEven #-}
@@ -41,7 +44,7 @@ maxValue = value + 1000
41{-# INLINE composeAllInFilters #-}
44{-# INLINE composeAllInFilters #-}
42{-# INLINE composeAllOutFilters #-}
45{-# INLINE composeAllOutFilters #-}
43{-# INLINE composeMapAllInFilter #-}
46{-# INLINE composeMapAllInFilter #-}
44−scan, map, filterEven, filterAllOut,
47+toNull, uncons, nullHeadTail, scan, map, filterEven, filterAllOut,
45 filterAllIn, takeOne, takeAll, takeWhileTrue, dropAll, dropWhileTrue, zip,
48 filterAllIn, takeOne, takeAll, takeWhileTrue, dropAll, dropWhileTrue, zip,
46 concat, composeAllInFilters, composeAllOutFilters,
49 concat, composeAllInFilters, composeAllOutFilters,
47 composeMapAllInFilter
50 composeMapAllInFilter
@@ -58,9 +61,7 @@ foldl :: Monad m => Stream m Int -> m Int
58{-# INLINE last #-}
61{-# INLINE last #-}
59last :: Monad m => Stream m Int -> m (Maybe Int)
62last :: Monad m => Stream m Int -> m (Maybe Int)
60
63
61−{-# INLINE toNull #-}
62{-# INLINE mapM #-}
64{-# INLINE mapM #-}
63−toNull :: Monad m => Stream m Int -> m ()
64mapM :: S.MonadAsync m => Stream m Int -> m ()
65mapM :: S.MonadAsync m => Stream m Int -> m ()
65
66
66-------------------------------------------------------------------------------
67-------------------------------------------------------------------------------
@@ -122,6 +123,23 @@ runStream :: Monad m => Stream m a -> m ()
122runStream = S.runStream
123runStream = S.runStream
123
124
124toNull = runStream
125toNull = runStream
126+uncons s = do
127+ r <- S.uncons s
128+ case r of
129+ Nothing -> return ()
130+ Just (_, t) -> uncons t
131+
132+nullHeadTail s = do
133+ r <- S.null s
134+ if not r
135+ then do
136+ _ <- S.head s
137+ t <- S.tail s
138+ case t of
139+ Nothing -> return ()
140+ Just x -> nullHeadTail x
141+ else return ()
142+
125toList = S.toList
143toList = S.toList
126foldl = S.foldl' (+) 0
144foldl = S.foldl' (+) 0
127last = S.last
145last = S.last
src/Streamly/Prelude.hs+7−20
@@ -210,11 +210,7 @@ toStreamD = D.fromStreamK . toStream
210--
210--
211-- @since 0.1.0
211-- @since 0.1.0
212uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
212uncons :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (a, t m a))
213−uncons m =
213+uncons m = K.uncons (K.adapt m)
214− let stop = return Nothing
215− single a = return (Just (a, K.nil))
216− yieldk a r = return (Just (a, fromStream r))
217− in (K.unStream (toStream m)) Nothing stop single yieldk
218
214
219------------------------------------------------------------------------------
215------------------------------------------------------------------------------
220-- Generation by Unfolding
216-- Generation by Unfolding
@@ -500,32 +496,23 @@ foldlM' step begin m = S.foldlM' step begin $ toStreamS m
500-- | Determine whether the stream is empty.
496-- | Determine whether the stream is empty.
501--
497--
502-- @since 0.1.1
498-- @since 0.1.1
499+{-# INLINE null #-}
503null :: Monad m => SerialT m a -> m Bool
500null :: Monad m => SerialT m a -> m Bool
504−null m =
501+null m = K.null m
505− let stop = return True
506− single _ = return False
507− yieldk _ _ = return False
508− in (K.unStream (toStream m)) Nothing stop single yieldk
509
502
510-- | Extract the first element of the stream, if any.
503-- | Extract the first element of the stream, if any.
511--
504--
512-- @since 0.1.0
505-- @since 0.1.0
506+{-# INLINE head #-}
513head :: Monad m => SerialT m a -> m (Maybe a)
507head :: Monad m => SerialT m a -> m (Maybe a)
514−head m =
508+head m = K.head m
515− let stop = return Nothing
516− single a = return (Just a)
517− yieldk a _ = return (Just a)
518− in (K.unStream (toStream m)) Nothing stop single yieldk
519
509
520-- | Extract all but the first element of the stream, if any.
510-- | Extract all but the first element of the stream, if any.
521--
511--
522-- @since 0.1.1
512-- @since 0.1.1
513+{-# INLINE tail #-}
523tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
514tail :: (IsStream t, Monad m) => SerialT m a -> m (Maybe (t m a))
524−tail m =
515+tail m = K.tail (K.adapt m)
525− let stop = return Nothing
526− single _ = return $ Just K.nil
527− yieldk _ r = return $ Just $ fromStream r
528− in (K.unStream (toStream m)) Nothing stop single yieldk
529
516
530-- | Extract the last element of the stream, if any.
517-- | Extract the last element of the stream, if any.
531--
518--
src/Streamly/Streams/StreamD.hs+40−3
@@ -30,7 +30,7 @@
30-- import qualified Streamly.Streams.StreamD as D
30-- import qualified Streamly.Streams.StreamD as D
31-- @
31-- @
32
32
33−-- A majority of functions in this file have been adapted from the vector
33+-- Some of functions in this file have been adapted from the vector
34-- library, https://hackage.haskell.org/package/vector.
34-- library, https://hackage.haskell.org/package/vector.
35
35
36module Streamly.Streams.StreamD
36module Streamly.Streams.StreamD
@@ -74,6 +74,9 @@ module Streamly.Streams.StreamD
74
74
75 -- ** Specialized Folds
75 -- ** Specialized Folds
76 , runStream
76 , runStream
77+ , null
78+ , head
79+ , tail
77 , last
80 , last
78 , elem
81 , elem
79 , notElem
82 , notElem
@@ -119,7 +122,7 @@ import GHC.Types ( SPEC(..) )
119import Prelude
122import Prelude
120 hiding (map, mapM, mapM_, repeat, foldr, last, take, filter,
123 hiding (map, mapM, mapM_, repeat, foldr, last, take, filter,
121 takeWhile, drop, dropWhile, all, any, maximum, minimum, elem,
124 takeWhile, drop, dropWhile, all, any, maximum, minimum, elem,
122− notElem)
125+ notElem, null, head, tail)
123
126
124import Streamly.SVar (MonadAsync)
127import Streamly.SVar (MonadAsync)
125import qualified Streamly.Streams.StreamK as K
128import qualified Streamly.Streams.StreamK as K
@@ -151,7 +154,7 @@ data Stream m a = forall s. Stream (s -> m (Step s a)) s
151nil :: Monad m => Stream m a
154nil :: Monad m => Stream m a
152nil = Stream (const $ return Stop) ()
155nil = Stream (const $ return Stop) ()
153
156
154−-- | Note that the cons operation is not scalable as it has O(n^2) complexity.
157+-- | Can fuse but has O(n^2) complexity.
155cons :: Monad m => a -> Stream m a -> Stream m a
158cons :: Monad m => a -> Stream m a -> Stream m a
156cons x (Stream step state) = Stream step1 Nothing
159cons x (Stream step state) = Stream step1 Nothing
157 where
160 where
@@ -166,6 +169,7 @@ cons x (Stream step state) = Stream step1 Nothing
166-- Deconstruction
169-- Deconstruction
167-------------------------------------------------------------------------------
170-------------------------------------------------------------------------------
168
171
172+-- Does not fuse, has the same performance as the StreamK version.
169{-# INLINE_NORMAL uncons #-}
173{-# INLINE_NORMAL uncons #-}
170uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
174uncons :: Monad m => Stream m a -> m (Maybe (a, Stream m a))
171uncons (Stream step state) = go state
175uncons (Stream step state) = go state
@@ -311,6 +315,39 @@ runStream (Stream step state) = go SPEC state
311 Yield _ s -> go SPEC s
315 Yield _ s -> go SPEC s
312 Stop -> return ()
316 Stop -> return ()
313
317
318+{-# INLINE_NORMAL null #-}
319+null :: Monad m => Stream m a -> m Bool
320+null (Stream step state) = go state
321+ where
322+ go st = do
323+ r <- step st
324+ case r of
325+ Yield _ _ -> return False
326+ Stop -> return True
327+
328+-- XXX SPEC?
329+{-# INLINE_NORMAL head #-}
330+head :: Monad m => Stream m a -> m (Maybe a)
331+head (Stream step state) = go state
332+ where
333+ go st = do
334+ r <- step st
335+ case r of
336+ Yield x _ -> return (Just x)
337+ Stop -> return Nothing
338+
339+-- Does not fuse, has the same performance as the StreamK version.
340+{-# INLINE_NORMAL tail #-}
341+tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
342+tail (Stream step state) = go state
343+ where
344+ go st = do
345+ r <- step st
346+ case r of
347+ Yield _ s -> return (Just $ Stream step s)
348+ Stop -> return Nothing
349+
350+-- XXX will it fuse? need custom impl?
314{-# INLINE_NORMAL last #-}
351{-# INLINE_NORMAL last #-}
315last :: Monad m => Stream m a -> m (Maybe a)
352last :: Monad m => Stream m a -> m (Maybe a)
316last = foldl' (\_ y -> Just y) Nothing
353last = foldl' (\_ y -> Just y) Nothing
src/Streamly/Streams/StreamK.hs+45−2
@@ -48,6 +48,9 @@ module Streamly.Streams.StreamK
48 , yieldK
48 , yieldK
49 , consK
49 , consK
50
50
51+ -- * Deconstruction
52+ , uncons
53+
51 -- * Generation
54 -- * Generation
52 -- ** Unfolds
55 -- ** Unfolds
53 , unfoldr
56 , unfoldr
@@ -75,6 +78,9 @@ module Streamly.Streams.StreamK
75
78
76 -- ** Specialized Folds
79 -- ** Specialized Folds
77 , runStream
80 , runStream
81+ , null
82+ , head
83+ , tail
78 , elem
84 , elem
79 , notElem
85 , notElem
80 , all
86 , all
@@ -131,7 +137,7 @@ import Data.Semigroup (Semigroup(..))
131import Prelude
137import Prelude
132 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
138 hiding (foldl, foldr, last, map, mapM, mapM_, repeat, sequence,
133 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
139 take, filter, all, any, takeWhile, drop, dropWhile, minimum,
134− maximum, elem, notElem)
140+ maximum, elem, notElem, null, head, tail)
135import qualified Prelude
141import qualified Prelude
136
142
137import Streamly.SVar
143import Streamly.SVar
@@ -337,6 +343,18 @@ instance IsStream Stream where
337 (|:) :: Monad m => m a -> Stream m a -> Stream m a
343 (|:) :: Monad m => m a -> Stream m a -> Stream m a
338 (|:) = consMSerial
344 (|:) = consMSerial
339
345
346+-------------------------------------------------------------------------------
347+-- Deconstruction
348+-------------------------------------------------------------------------------
349+
350+{-# INLINE uncons #-}
351+uncons :: (IsStream t, Monad m) => t m a -> m (Maybe (a, t m a))
352+uncons m =
353+ let stop = return Nothing
354+ single a = return (Just (a, nil))
355+ yieldk a r = return (Just (a, fromStream r))
356+ in (unStream (toStream m)) Nothing stop single yieldk
357+
340-------------------------------------------------------------------------------
358-------------------------------------------------------------------------------
341-- Generation
359-- Generation
342-------------------------------------------------------------------------------
360-------------------------------------------------------------------------------
@@ -514,6 +532,7 @@ foldlM' step begin m = foldxM step (return begin) return m
514-- Specialized folds
532-- Specialized folds
515------------------------------------------------------------------------------
533------------------------------------------------------------------------------
516
534
535+{-# INLINE runStream #-}
517runStream :: (Monad m, IsStream t) => t m a -> m ()
536runStream :: (Monad m, IsStream t) => t m a -> m ()
518runStream m = go (toStream m)
537runStream m = go (toStream m)
519 where
538 where
@@ -521,7 +540,31 @@ runStream m = go (toStream m)
521 let stop = return ()
540 let stop = return ()
522 single _ = return ()
541 single _ = return ()
523 yieldk _ r = go (toStream r)
542 yieldk _ r = go (toStream r)
543+ in unStream m1 Nothing stop single yieldk
544+
545+{-# INLINE null #-}
546+null :: (IsStream t, Monad m) => t m a -> m Bool
547+null m =
548+ let stop = return True
549+ single _ = return False
550+ yieldk _ _ = return False
551+ in unStream (toStream m) Nothing stop single yieldk
552+
553+{-# INLINE head #-}
554+head :: (IsStream t, Monad m) => t m a -> m (Maybe a)
555+head m =
556+ let stop = return Nothing
557+ single a = return (Just a)
558+ yieldk a _ = return (Just a)
559+ in unStream (toStream m) Nothing stop single yieldk
560+
561+{-# INLINE tail #-}
562+tail :: (IsStream t, Monad m) => t m a -> m (Maybe (t m a))
563+tail m =
564+ let stop = return Nothing
565+ single _ = return $ Just nil
566+ yieldk _ r = return $ Just $ fromStream r
524− in (unStream m1) Nothing stop single yieldk
567+ in unStream (toStream m) Nothing stop single yieldk
525
568
526{-# INLINE elem #-}
569{-# INLINE elem #-}
527elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool
570elem :: (IsStream t, Monad m, Eq a) => a -> t m a -> m Bool