on master help sign in
add direct versions of monolithic scan/map and fold/map
db2c560Harendra Kumar
Changelog.md+4
@@ -3,6 +3,7 @@
3### Breaking changes
3### Breaking changes
4
4
5* Change the signature of `foldrM` to ensure that it is lazy
5* Change the signature of `foldrM` to ensure that it is lazy
6+* `scanx` would require an additional `Monad m` constraint.
6
7
7### Enhancements
8### Enhancements
8
9
@@ -21,6 +22,9 @@
21* `runStream`, `foldWith`, `foldMapWith`, `forEachWith` have been moved from
22* `runStream`, `foldWith`, `foldMapWith`, `forEachWith` have been moved from
22 "Streamly" module to "Streamly.Prelude" module.
23 "Streamly" module to "Streamly.Prelude" module.
23
24
25+* Deprecate `scanx`, `foldx`, `foldxM`
26+* Remove deprecated APIs `scan`, `foldl`, `foldlM`
27+
24## 0.6.1
28## 0.6.1
25
29
26### Bug Fixes
30### Bug Fixes
benchmark/Linear.hs+7−2
@@ -178,7 +178,7 @@ main =
178 , benchIOSink "toRevList" Ops.toRevList
178 , benchIOSink "toRevList" Ops.toRevList
179 ]
179 ]
180 , bgroup "transformation"
180 , bgroup "transformation"
181− [ benchIOSink "scan" (Ops.scan 1)
181+ [ benchIOSink "scanl" (Ops.scan 1)
182 , benchIOSink "scanl1'" (Ops.scanl1' 1)
182 , benchIOSink "scanl1'" (Ops.scanl1' 1)
183 , benchIOSink "map" (Ops.map 1)
183 , benchIOSink "map" (Ops.map 1)
184 , benchIOSink "fmap" (Ops.fmap 1)
184 , benchIOSink "fmap" (Ops.fmap 1)
@@ -249,8 +249,13 @@ main =
249 , benchIOSink "stripPrefix" Ops.stripPrefix
249 , benchIOSink "stripPrefix" Ops.stripPrefix
250 , benchIOSrc serially "concatMap" Ops.concatMap
250 , benchIOSrc serially "concatMap" Ops.concatMap
251 ]
251 ]
252+ -- scanl-map and foldl-map are equivalent to the scan and fold in the foldl
253+ -- library. If scan/fold followed by a map is efficient enough we may not
254+ -- need monolithic implementations of these.
252 , bgroup "mixed"
255 , bgroup "mixed"
256+ [ benchIOSink "scanl-map" (Ops.scanMap 1)
257+ , benchIOSink "foldl-map" Ops.foldl'ReduceMap
253− [ benchIOSink "sum-product-fold" Ops.sumProductFold
258+ , benchIOSink "sum-product-fold" Ops.sumProductFold
254 , benchIOSink "sum-product-scan" Ops.sumProductScan
259 , benchIOSink "sum-product-scan" Ops.sumProductScan
255 ]
260 ]
256 , bgroup "mixedX4"
261 , bgroup "mixedX4"
benchmark/LinearOps.hs+3−1
@@ -181,12 +181,13 @@ head, last, minimum, maximum, find, findIndex, elemIndex, foldl1'Reduce
181minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
181minimumBy, maximumBy :: Monad m => Stream m Int -> m (Maybe Int)
182
182
183{-# INLINE foldl'Reduce #-}
183{-# INLINE foldl'Reduce #-}
184+{-# INLINE foldl'ReduceMap #-}
184{-# INLINE foldlM'Reduce #-}
185{-# INLINE foldlM'Reduce #-}
185{-# INLINE foldrMReduce #-}
186{-# INLINE foldrMReduce #-}
186{-# INLINE length #-}
187{-# INLINE length #-}
187{-# INLINE sum #-}
188{-# INLINE sum #-}
188{-# INLINE product #-}
189{-# INLINE product #-}
189−foldl'Reduce, foldlM'Reduce, foldrMReduce, length, sum, product
190+foldl'Reduce, foldl'ReduceMap, foldlM'Reduce, foldrMReduce, length, sum, product
190 :: Monad m
191 :: Monad m
191 => Stream m Int -> m Int
192 => Stream m Int -> m Int
192
193
@@ -250,6 +251,7 @@ foldlM'Build = S.foldlM' (\xs x -> return $ x : xs) []
250
251
251foldrMReduce = S.foldrM (\x xs -> xs >>= return . (x +)) (return 0)
252foldrMReduce = S.foldrM (\x xs -> xs >>= return . (x +)) (return 0)
252foldl'Reduce = S.foldl' (+) 0
253foldl'Reduce = S.foldl' (+) 0
254+foldl'ReduceMap = P.fmap (+1) . S.foldl' (+) 0
253foldl1'Reduce = S.foldl1' (+)
255foldl1'Reduce = S.foldl1' (+)
254foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
256foldlM'Reduce = S.foldlM' (\xs a -> return $ a + xs) 0
255
257
src/Streamly/Prelude.hs+8−26
@@ -180,8 +180,6 @@ module Streamly.Prelude
180 , foldl'
180 , foldl'
181 , foldl1'
181 , foldl1'
182 , foldlM'
182 , foldlM'
183− , foldx
184− , foldxM
185
183
186 -- ** Strict Full Folds
184 -- ** Strict Full Folds
187 -- | Folds that are guaranteed to evaluate the whole stream.
185 -- | Folds that are guaranteed to evaluate the whole stream.
@@ -321,7 +319,6 @@ module Streamly.Prelude
321 -- , prescanlM'
319 -- , prescanlM'
322 , scanl1'
320 , scanl1'
323 , scanl1M'
321 , scanl1M'
324− , scanx
325
322
326 , indexed
323 , indexed
327 , indexedR
324 , indexedR
@@ -458,11 +455,11 @@ module Streamly.Prelude
458 -- * Deprecated
455 -- * Deprecated
459 , K.once
456 , K.once
460 , each
457 , each
461− , scan
458+ , scanx
462 , foldr
459 , foldr
463 , foldr1
460 , foldr1
464− , foldl
461+ , foldx
465− , foldlM
462+ , foldxM
466 )
463 )
467where
464where
468
465
@@ -1027,16 +1024,11 @@ foldr1 f m = S.foldr1 f (toStreamS m)
1027-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1024-- @foldl@ library. The suffix @x@ is a mnemonic for extraction.
1028--
1025--
1029-- @since 0.2.0
1026-- @since 0.2.0
1027+{-# DEPRECATED foldx "Please use foldl' followed by fmap instead." #-}
1030{-# INLINE foldx #-}
1028{-# INLINE foldx #-}
1031foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1029foldx :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1032foldx = P.foldlx'
1030foldx = P.foldlx'
1033
1031
1034−-- |
1035−-- @since 0.1.0
1036−{-# DEPRECATED foldl "Please use foldx instead." #-}
1037−foldl :: Monad m => (x -> a -> x) -> x -> (x -> b) -> SerialT m a -> m b
1038−foldl = P.foldlx'
1039−
1040-- | Strict left associative/push fold. Note that the observations below about
1032-- | Strict left associative/push fold. Note that the observations below about
1041-- the behavior of a left fold assume that we are working on a right associated
1033-- the behavior of a left fold assume that we are working on a right associated
1042-- structure like cons lists and streamly streams. If we are working on a left
1034-- structure like cons lists and streamly streams. If we are working on a left
@@ -1150,16 +1142,11 @@ foldl1' step m = do
1150-- | Like 'foldx', but with a monadic step function.
1142-- | Like 'foldx', but with a monadic step function.
1151--
1143--
1152-- @since 0.2.0
1144-- @since 0.2.0
1145+{-# DEPRECATED foldxM "Please use foldlM' followed by fmap instead." #-}
1153{-# INLINE foldxM #-}
1146{-# INLINE foldxM #-}
1154foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1147foldxM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1155foldxM = P.foldlMx'
1148foldxM = P.foldlMx'
1156
1149
1157−-- |
1158−-- @since 0.1.0
1159−{-# DEPRECATED foldlM "Please use foldxM instead." #-}
1160−foldlM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> SerialT m a -> m b
1161−foldlM = P.foldlMx'
1162−
1163-- | Like 'foldl'' but with a monadic step function.
1150-- | Like 'foldl'' but with a monadic step function.
1164--
1151--
1165-- @since 0.2.0
1152-- @since 0.2.0
@@ -1543,15 +1530,10 @@ toHandle h m = go m
1543-- extraction.
1530-- extraction.
1544--
1531--
1545-- @since 0.2.0
1532-- @since 0.2.0
1533+{-# DEPRECATED scanx "Please use scanl followed by map instead." #-}
1546{-# INLINE scanx #-}
1534{-# INLINE scanx #-}
1547−scanx :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
1535+scanx :: (IsStream t, Monad m) => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
1548−scanx = K.scanx'
1536+scanx = P.scanlx'
1549−
1550−-- |
1551−-- @since 0.1.1
1552−{-# DEPRECATED scan "Please use scanx instead." #-}
1553−scan :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
1554−scan = scanx
1555
1537
1556-- XXX this needs to be concurrent
1538-- XXX this needs to be concurrent
1557-- | Like 'scanl'' but with a monadic fold function.
1539-- | Like 'scanl'' but with a monadic fold function.
src/Streamly/Streams/Prelude.hs+45
@@ -42,6 +42,11 @@ module Streamly.Streams.Prelude
42 , foldlS
42 , foldlS
43 , foldlT
43 , foldlT
44
44
45+ , scanlx'
46+ , scanlMx'
47+ , postscanlx'
48+ , postscanlMx'
49+
45 -- * Zip style operations
50 -- * Zip style operations
46 , eqBy
51 , eqBy
47 , cmpBy
52 , cmpBy
@@ -174,6 +179,46 @@ foldlT :: (Monad m, IsStream t, Monad (s m), MonadTrans s)
174 => (s m b -> a -> s m b) -> s m b -> t m a -> s m b
179 => (s m b -> a -> s m b) -> s m b -> t m a -> s m b
175foldlT f z s = S.foldlT f z (toStreamS s)
180foldlT f z s = S.foldlT f z (toStreamS s)
176
181
182+------------------------------------------------------------------------------
183+-- Scans
184+------------------------------------------------------------------------------
185+
186+-- postscanlM' followed by mapM
187+{-# INLINE postscanlMx' #-}
188+postscanlMx' :: (IsStream t, Monad m)
189+ => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
190+postscanlMx' step begin done m =
191+ D.fromStreamD $ D.postscanlMx' step begin done $ D.toStreamD m
192+
193+-- postscanl' followed by map
194+{-# INLINE postscanlx' #-}
195+postscanlx' :: (IsStream t, Monad m)
196+ => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
197+postscanlx' step begin done m =
198+ D.fromStreamD $ D.postscanlx' step begin done $ D.toStreamD m
199+
200+-- scanlM' followed by mapM
201+--
202+{-# INLINE scanlMx' #-}
203+scanlMx' :: (IsStream t, Monad m)
204+ => (x -> a -> m x) -> m x -> (x -> m b) -> t m a -> t m b
205+scanlMx' step begin done m =
206+ D.fromStreamD $ D.scanlMx' step begin done $ D.toStreamD m
207+
208+-- scanl followed by map
209+--
210+-- | Strict left scan with an extraction function. Like 'scanl'', but applies a
211+-- user supplied extraction function (the third argument) at each step. This is
212+-- designed to work with the @foldl@ library. The suffix @x@ is a mnemonic for
213+-- extraction.
214+--
215+-- @since 0.7.0
216+{-# INLINE scanlx' #-}
217+scanlx' :: (IsStream t, Monad m)
218+ => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
219+scanlx' step begin done m =
220+ fromStreamS $ S.scanlx' step begin done $ toStreamS m
221+
177------------------------------------------------------------------------------
222------------------------------------------------------------------------------
178-- Comparison
223-- Comparison
179------------------------------------------------------------------------------
224------------------------------------------------------------------------------
src/Streamly/Streams/StreamD.hs+77
@@ -155,11 +155,17 @@ module Streamly.Streams.StreamD
155
155
156 , prescanl'
156 , prescanl'
157 , prescanlM'
157 , prescanlM'
158+
158 , postscanl
159 , postscanl
159 , postscanlM
160 , postscanlM
160 , postscanl'
161 , postscanl'
161 , postscanlM'
162 , postscanlM'
162
163
164+ , postscanlx'
165+ , postscanlMx'
166+ , scanlMx'
167+ , scanlx'
168+
163 -- * Filtering
169 -- * Filtering
164 , filter
170 , filter
165 , filterM
171 , filterM
@@ -229,6 +235,23 @@ import qualified Streamly.Streams.StreamK as K
229nil :: Monad m => Stream m a
235nil :: Monad m => Stream m a
230nil = Stream (\_ _ -> return Stop) ()
236nil = Stream (\_ _ -> return Stop) ()
231
237
238+{-# INLINE_NORMAL consM #-}
239+consM :: Monad m => m a -> Stream m a -> Stream m a
240+consM m (Stream step state) = Stream step1 Nothing
241+ where
242+ {-# INLINE_LATE step1 #-}
243+ step1 _ Nothing = m >>= \x -> return $ Yield x (Just state)
244+ step1 gst (Just st) = do
245+ r <- step gst st
246+ return $
247+ case r of
248+ Yield a s -> Yield a (Just s)
249+ Skip s -> Skip (Just s)
250+ Stop -> Stop
251+
252+-- XXX implement in terms of consM?
253+-- cons x = consM (return x)
254+--
232-- | Can fuse but has O(n^2) complexity.
255-- | Can fuse but has O(n^2) complexity.
233{-# INLINE_NORMAL cons #-}
256{-# INLINE_NORMAL cons #-}
234cons :: Monad m => a -> Stream m a -> Stream m a
257cons :: Monad m => a -> Stream m a -> Stream m a
@@ -983,6 +1006,10 @@ fromStreamD = K.fromStream . toStreamK
983-- Transformation by Folding (Scans)
1006-- Transformation by Folding (Scans)
984------------------------------------------------------------------------------
1007------------------------------------------------------------------------------
985
1008
1009+------------------------------------------------------------------------------
1010+-- Prescans
1011+------------------------------------------------------------------------------
1012+
986-- XXX Is a prescan useful, discarding the last step does not sound useful? I
1013-- XXX Is a prescan useful, discarding the last step does not sound useful? I
987-- am not sure about the utility of this function, so this is implemented but
1014-- am not sure about the utility of this function, so this is implemented but
988-- not exposed. We can expose it if someone provides good reasons why this is
1015-- not exposed. We can expose it if someone provides good reasons why this is
@@ -1011,6 +1038,56 @@ prescanlM' f mz (Stream step state) = Stream step' (state, mz)
1011prescanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
1038prescanl' :: Monad m => (b -> a -> b) -> b -> Stream m a -> Stream m b
1012prescanl' f z = prescanlM' (\a b -> return (f a b)) (return z)
1039prescanl' f z = prescanlM' (\a b -> return (f a b)) (return z)
1013
1040
1041+------------------------------------------------------------------------------
1042+-- Monolithic postscans (postscan followed by a map)
1043+------------------------------------------------------------------------------
1044+
1045+-- The performance of a modular postscan followed by a map seems to be
1046+-- equivalent to this monolithic scan followed by map therefore we may not need
1047+-- this implementation. We just have it for performance comparison and in case
1048+-- modular version does not perform well in some situation.
1049+--
1050+{-# INLINE_NORMAL postscanlMx' #-}
1051+postscanlMx' :: Monad m
1052+ => (x -> a -> m x) -> m x -> (x -> m b) -> Stream m a -> Stream m b
1053+postscanlMx' fstep begin done (Stream step state) = do
1054+ Stream step' (state, begin)
1055+ where
1056+ {-# INLINE_LATE step' #-}
1057+ step' gst (st, acc) = do
1058+ r <- step (adaptState gst) st
1059+ case r of
1060+ Yield x s -> do
1061+ old <- acc
1062+ y <- fstep old x
1063+ v <- done y
1064+ v `seq` y `seq` return (Yield v (s, return y))
1065+ Skip s -> return $ Skip (s, acc)
1066+ Stop -> return Stop
1067+
1068+{-# INLINE_NORMAL postscanlx' #-}
1069+postscanlx' :: Monad m
1070+ => (x -> a -> x) -> x -> (x -> b) -> Stream m a -> Stream m b
1071+postscanlx' fstep begin done s =
1072+ postscanlMx' (\b a -> return (fstep b a)) (return begin) (return . done) s
1073+
1074+-- XXX do we need consM strict to evaluate the begin value?
1075+{-# INLINE scanlMx' #-}
1076+scanlMx' :: Monad m
1077+ => (x -> a -> m x) -> m x -> (x -> m b) -> Stream m a -> Stream m b
1078+scanlMx' fstep begin done s =
1079+ (begin >>= \x -> x `seq` done x) `consM` postscanlMx' fstep begin done s
1080+
1081+{-# INLINE scanlx' #-}
1082+scanlx' :: Monad m
1083+ => (x -> a -> x) -> x -> (x -> b) -> Stream m a -> Stream m b
1084+scanlx' fstep begin done s =
1085+ scanlMx' (\b a -> return (fstep b a)) (return begin) (return . done) s
1086+
1087+------------------------------------------------------------------------------
1088+-- postscans
1089+------------------------------------------------------------------------------
1090+
1014-- XXX if we make the initial value of the accumulator monadic then should we
1091-- XXX if we make the initial value of the accumulator monadic then should we
1015-- execute it even if the stream is empty? In that case we would have generated
1092-- execute it even if the stream is empty? In that case we would have generated
1016-- the effect but discarded the value, but that is what a fold does when the
1093-- the effect but discarded the value, but that is what a fold does when the
src/Streamly/Streams/StreamK.hs+5−5
@@ -117,7 +117,7 @@ module Streamly.Streams.StreamK
117 -- * Transformation
117 -- * Transformation
118 -- ** By folding (scans)
118 -- ** By folding (scans)
119 , scanl'
119 , scanl'
120− , scanx'
120+ , scanlx'
121
121
122 -- ** Filtering
122 -- ** Filtering
123 , filter
123 , filter
@@ -757,9 +757,9 @@ toStreamK = id
757-- Transformation by folding (Scans)
757-- Transformation by folding (Scans)
758-------------------------------------------------------------------------------
758-------------------------------------------------------------------------------
759
759
760−{-# INLINE scanx' #-}
760+{-# INLINE scanlx' #-}
761−scanx' :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
761+scanlx' :: IsStream t => (x -> a -> x) -> x -> (x -> b) -> t m a -> t m b
762−scanx' step begin done m =
762+scanlx' step begin done m =
763 cons (done begin) $ go m begin
763 cons (done begin) $ go m begin
764 where
764 where
765 go m1 !acc = mkStream $ \st yld sng stp ->
765 go m1 !acc = mkStream $ \st yld sng stp ->
@@ -771,7 +771,7 @@ scanx' step begin done m =
771
771
772{-# INLINE scanl' #-}
772{-# INLINE scanl' #-}
773scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
773scanl' :: IsStream t => (b -> a -> b) -> b -> t m a -> t m b
774−scanl' step begin = scanx' step begin id
774+scanl' step begin = scanlx' step begin id
775
775
776-------------------------------------------------------------------------------
776-------------------------------------------------------------------------------
777-- Filtering
777-- Filtering
test/Main.hs+10−2
@@ -490,11 +490,13 @@ parallelTests = H.parallel $ do
490 -- Left folds are strict enough
490 -- Left folds are strict enough
491 ---------------------------------------------------------------------------
491 ---------------------------------------------------------------------------
492
492
493+#ifdef DEVBUILD
493 it "foldx is strict enough" checkFoldxStrictness
494 it "foldx is strict enough" checkFoldxStrictness
494− it "foldl' is strict enough" checkFoldl'Strictness
495 it "scanx is strict enough" checkScanxStrictness
495 it "scanx is strict enough" checkScanxStrictness
496− it "scanl' is strict enough" checkScanl'Strictness
497 it "foldxM is strict enough" (checkFoldMStrictness foldxMStrictCheck)
496 it "foldxM is strict enough" (checkFoldMStrictness foldxMStrictCheck)
497+#endif
498+ it "foldl' is strict enough" checkFoldl'Strictness
499+ it "scanl' is strict enough" checkScanl'Strictness
498 it "foldlM' is strict enough" (checkFoldMStrictness foldlM'StrictCheck)
500 it "foldlM' is strict enough" (checkFoldMStrictness foldlM'StrictCheck)
499 it "scanlM' is strict enough" (checkScanlMStrictness scanlM'StrictCheck)
501 it "scanlM' is strict enough" (checkScanlMStrictness scanlM'StrictCheck)
500
502
@@ -645,6 +647,7 @@ checkFoldrLaziness = do
645 $ (S.fromList (2:4:5:undefined) :: SerialT IO Int))
647 $ (S.fromList (2:4:5:undefined) :: SerialT IO Int))
646 `shouldReturn` [True]
648 `shouldReturn` [True]
647
649
650+#ifdef DEVBUILD
648checkFoldxStrictness :: IO ()
651checkFoldxStrictness :: IO ()
649checkFoldxStrictness = do
652checkFoldxStrictness = do
650 let s = return (1 :: Int) `S.consM` error "failure"
653 let s = return (1 :: Int) `S.consM` error "failure"
@@ -654,6 +657,7 @@ checkFoldxStrictness = do
654 ErrorCall err -> return err
657 ErrorCall err -> return err
655 _ -> throw e)
658 _ -> throw e)
656 `shouldReturn` "success"
659 `shouldReturn` "success"
660+#endif
657
661
658checkFoldl'Strictness :: IO ()
662checkFoldl'Strictness :: IO ()
659checkFoldl'Strictness = do
663checkFoldl'Strictness = do
@@ -665,6 +669,7 @@ checkFoldl'Strictness = do
665 _ -> throw e)
669 _ -> throw e)
666 `shouldReturn` "success"
670 `shouldReturn` "success"
667
671
672+#ifdef DEVBUILD
668checkScanxStrictness :: IO ()
673checkScanxStrictness :: IO ()
669checkScanxStrictness = do
674checkScanxStrictness = do
670 let s = return (1 :: Int) `S.consM` error "failure"
675 let s = return (1 :: Int) `S.consM` error "failure"
@@ -682,6 +687,7 @@ checkScanxStrictness = do
682 ErrorCall err -> return err
687 ErrorCall err -> return err
683 _ -> throw e)
688 _ -> throw e)
684 `shouldReturn` "success"
689 `shouldReturn` "success"
690+#endif
685
691
686checkScanl'Strictness :: IO ()
692checkScanl'Strictness :: IO ()
687checkScanl'Strictness = do
693checkScanl'Strictness = do
@@ -705,8 +711,10 @@ checkScanl'Strictness = do
705foldlM'StrictCheck :: IORef Int -> SerialT IO Int -> IO ()
711foldlM'StrictCheck :: IORef Int -> SerialT IO Int -> IO ()
706foldlM'StrictCheck ref = S.foldlM' (\_ _ -> writeIORef ref 1) ()
712foldlM'StrictCheck ref = S.foldlM' (\_ _ -> writeIORef ref 1) ()
707
713
714+#ifdef DEVBUILD
708foldxMStrictCheck :: IORef Int -> SerialT IO Int -> IO ()
715foldxMStrictCheck :: IORef Int -> SerialT IO Int -> IO ()
709foldxMStrictCheck ref = S.foldxM (\_ _ -> writeIORef ref 1) (return ()) return
716foldxMStrictCheck ref = S.foldxM (\_ _ -> writeIORef ref 1) (return ()) return
717+#endif
710
718
711checkFoldMStrictness :: (IORef Int -> SerialT IO Int -> IO ()) -> IO ()
719checkFoldMStrictness :: (IORef Int -> SerialT IO Int -> IO ()) -> IO ()
712checkFoldMStrictness f = do
720checkFoldMStrictness f = do
test/nested-loops.hs+2−2
@@ -1,8 +1,8 @@
1import Control.Concurrent (myThreadId)
1import Control.Concurrent (myThreadId)
2import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
2import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
3import System.Random (randomIO)
3import System.Random (randomIO)
4−import Streamly
4+import Streamly hiding (runStream)
5−import Streamly.Prelude (nil, yieldM)
5+import Streamly.Prelude (runStream, nil, yieldM)
6
6
7main :: IO ()
7main :: IO ()
8main = runStream $ do
8main = runStream $ do