on master help sign in
Refactor Unfold module

* Rearrange exports, export additional functions * Update docs * Disable applicative/monad/category/arrow instances * Rename const to yieldM and add yield * Remove "effect", it can be expressed by yieldM * Change order of arguments for some functions

commita5e483b610564b747350d8f712672c1836a618a2 authorHarendra Kumar <harendra@composewell.com> dateThu 18 Mar 2021, 02:41 (6 years ago) parentde06529
10 files changed+332−148
benchmark/Streamly/Benchmark/Data/Unfold.hs+54−23 src/Streamly/Data/Unfold.hs+57−1 src/Streamly/Internal/Data/Unfold.hs+129−89 src/Streamly/Internal/Data/Unfold/Type.hs+79−16 src/Streamly/Internal/FileSystem/Handle.hs+2−2 src/Streamly/Internal/Network/Inet/TCP.hs+3−3 src/Streamly/Internal/Network/Socket.hs+2−2 test/Streamly/Test/Data/Unfold.hs+4−10 test/Streamly/Test/Prelude/Serial.hs+1−1 test/lib/Streamly/Test/Prelude/Common.hs+1−1
benchmark/Streamly/Benchmark/Data/Unfold.hs+54−23
@@ -115,7 +115,7 @@ lmapM size start =
115115{-# INLINE supply #-}
116116supply :: Monad m => Int -> Int -> m ()
117117supply size start =
118− drainTransformationDefault (size + start) (flip UF.supply start) undefined
118+ drainTransformationDefault (size + start) (UF.supply start) undefined
119119
120120
121121{-# INLINE supplyFirst #-}
@@ -123,7 +123,7 @@ supplyFirst :: Monad m => Int -> Int -> m ()
123123supplyFirst size start =
124124 drainTransformation
125125 (UF.take size UF.enumerateFromStepIntegral)
126− (flip UF.supplyFirst start)
126+ (UF.supplyFirst start)
127127 1
128128
129129{-# INLINE supplySecond #-}
@@ -131,7 +131,7 @@ supplySecond :: Monad m => Int -> Int -> m ()
131131supplySecond size start =
132132 drainTransformation
133133 (UF.take size UF.enumerateFromStepIntegral)
134− (flip UF.supplySecond 1)
134+ (UF.supplySecond 1)
135135 start
136136
137137{-# INLINE discardFirst #-}
@@ -181,11 +181,6 @@ consM :: Monad m => Int -> Int -> m ()
181181consM size start =
182182 drainTransformationDefault (size + start) (UF.consM return) start
183183
184−{-# INLINE _effect #-}
185−_effect :: Monad m => Int -> Int -> m ()
186−_effect _ start =
187− drainGeneration (UF.effect (return start)) undefined
188−
189184{-# INLINE _singletonM #-}
190185_singletonM :: Monad m => Int -> Int -> m ()
191186_singletonM _ start = drainGeneration (UF.singletonM return) start
@@ -201,7 +196,7 @@ _identity _ start = drainGeneration UF.identity start
201196{-# INLINE _const #-}
202197_const :: Monad m => Int -> Int -> m ()
203198_const size start =
204− drainGeneration (UF.take size (UF.const (return start))) undefined
199+ drainGeneration (UF.take size (UF.yieldM (return start))) undefined
205200
206201{-# INLINE unfoldrM #-}
207202unfoldrM :: Monad m => Int -> Int -> m ()
@@ -413,7 +408,8 @@ toNullAp :: Monad m => Int -> Int -> m ()
413408toNullAp value start =
414409 let end = start + nthRoot 2 value
415410 s = source end
416− in UF.fold ((+) <$> s <*> s) FL.drain start
411+ -- in UF.fold ((+) <$> s <*> s) FL.drain start
412+ in UF.fold ((+) `fmap` s `UF.apply` s) FL.drain start
417413
418414{-# INLINE _apDiscardFst #-}
419415_apDiscardFst :: Int -> Int -> m ()
@@ -446,10 +442,15 @@ toNull :: Monad m => Int -> Int -> m ()
446442toNull value start =
447443 let end = start + nthRoot 2 value
448444 src = source end
445+ {-
449446 u = do
450447 x <- src
451448 y <- src
452449 return (x + y)
450+ -}
451+ u = src `UF.bind` \x ->
452+ src `UF.bind` \y ->
453+ UF.yield (x + y)
453454 in UF.fold u FL.drain start
454455
455456
@@ -458,11 +459,16 @@ toNull3 :: Monad m => Int -> Int -> m ()
458459toNull3 value start =
459460 let end = start + nthRoot 3 value
460461 src = source end
462+ {-
461463 u = do
462464 x <- src
463465 y <- src
464466 z <- src
465467 return (x + y + z)
468+ -}
469+ u = src `UF.bind` \x ->
470+ src `UF.bind` \y ->
471+ UF.yield (x + y)
466472 in UF.fold u FL.drain start
467473
468474{-# INLINE toList #-}
@@ -470,10 +476,15 @@ toList :: Monad m => Int -> Int -> m [Int]
470476toList value start = do
471477 let end = start + nthRoot 2 value
472478 src = source end
479+ {-
473480 u = do
474481 x <- src
475482 y <- src
476483 return (x + y)
484+ -}
485+ u = src `UF.bind` \x ->
486+ src `UF.bind` \y ->
487+ UF.yield (x + y)
477488 in UF.fold u FL.toList start
478489
479490{-# INLINE toListSome #-}
@@ -481,10 +492,15 @@ toListSome :: Monad m => Int -> Int -> m [Int]
481492toListSome value start = do
482493 let end = start + nthRoot 2 value
483494 src = source end
495+ {-
484496 u = do
485497 x <- src
486498 y <- src
487499 return (x + y)
500+ -}
501+ u = src `UF.bind` \x ->
502+ src `UF.bind` \y ->
503+ UF.yield (x + y)
488504 in UF.fold (UF.take 1000 u) FL.toList start
489505
490506{-# INLINE filterAllOut #-}
@@ -492,13 +508,17 @@ filterAllOut :: Monad m => Int -> Int -> m ()
492508filterAllOut value start = do
493509 let end = start + nthRoot 2 value
494510 src = source end
511+ {-
495512 u = do
496513 x <- src
497514 y <- src
515+ -}
516+ u = src `UF.bind` \x ->
517+ src `UF.bind` \y ->
498518 let s = x + y
499− if s < 0
500− then return s
501− else UF.nilM (return . const ())
519+ in if s < 0
520+ then UF.yield s
521+ else UF.nilM (return . const ())
502522 in UF.fold u FL.drain start
503523
504524{-# INLINE filterAllIn #-}
@@ -506,13 +526,17 @@ filterAllIn :: Monad m => Int -> Int -> m ()
506526filterAllIn value start = do
507527 let end = start + nthRoot 2 value
508528 src = source end
529+ {-
509530 u = do
510531 x <- src
511532 y <- src
533+ -}
534+ u = src `UF.bind` \x ->
535+ src `UF.bind` \y ->
512536 let s = x + y
513− if s > 0
514− then return s
515− else UF.nilM (return . const ())
537+ in if s > 0
538+ then UF.yield s
539+ else UF.nilM (return . const ())
516540 in UF.fold u FL.drain start
517541
518542{-# INLINE filterSome #-}
@@ -520,13 +544,17 @@ filterSome :: Monad m => Int -> Int -> m ()
520544filterSome value start = do
521545 let end = start + nthRoot 2 value
522546 src = source end
547+ {-
523548 u = do
524549 x <- src
525550 y <- src
551+ -}
552+ u = src `UF.bind` \x ->
553+ src `UF.bind` \y ->
526554 let s = x + y
527− if s > 1100000
528− then return s
529− else UF.nilM (return . const ())
555+ in if s > 1100000
556+ then UF.yield s
557+ else UF.nilM (return . const ())
530558 in UF.fold u FL.drain start
531559
532560{-# INLINE breakAfterSome #-}
@@ -534,13 +562,17 @@ breakAfterSome :: Int -> Int -> IO ()
534562breakAfterSome value start =
535563 let end = start + nthRoot 2 value
536564 src = source end
565+ {-
537566 u = do
538567 x <- src
539568 y <- src
569+ -}
570+ u = src `UF.bind` \x ->
571+ src `UF.bind` \y ->
540572 let s = x + y
541− if s > 1100000
542− then error "break"
543− else return s
573+ in if s > 1100000
574+ then error "break"
575+ else UF.yield s
544576 in do
545577 (_ :: Either ErrorCall ()) <- try $ UF.fold u FL.drain start
546578 return ()
@@ -594,7 +626,6 @@ o_1_space_generation size =
594626 -- Very small benchmarks, reporting in ns
595627 -- , benchIO "nilM" $ nilM size
596628 , benchIO "consM" $ consM size
597− -- , benchIO "effect" $ effect size
598629 -- , benchIO "singletonM" $ singletonM size
599630 -- , benchIO "singleton" $ singleton size
600631 -- , benchIO "identity" $ identity size
src/Streamly/Data/Unfold.hs+57−1
@@ -55,8 +55,64 @@ module Streamly.Data.Unfold
5555 (
5656 -- * Unfold Type
5757 Unfold
58+
59+ -- * Folding
60+ , fold
61+
62+ -- * Unfolds
63+ -- One to one correspondence with
64+ -- "Streamly.Internal.Data.Stream.IsStream.Generate"
65+
66+ -- ** Generators
67+ -- | Generate a monadic stream from a seed.
68+ , unfoldrM
69+ , repeatM
70+ , replicateM
71+ , iterateM
72+
73+ -- ** From Containers
74+ , fromList
75+ , fromListM
76+ , fromStream
77+
78+ -- * Combinators
79+ -- ** Mapping on Input
80+ , lmap
81+ , lmapM
82+
83+ -- ** Mapping on Output
84+ , mapM
85+
86+ -- ** Filtering
87+ , takeWhileM
88+ , takeWhile
89+ , take
90+ , filter
91+ , filterM
92+ , drop
93+ , dropWhile
94+ , dropWhileM
95+
96+ -- ** Zipping
97+ , zipWithM
98+ , zipWith
99+
100+ -- ** Nesting
101+ , cross
102+ , many
103+
104+ -- ** Exceptions
105+ , before
106+ , after
107+ , onException
108+ , finally
109+ , bracket
110+ , handle
58111 )
59112where
60113
61−import Prelude hiding (concat, map, takeWhile, take, filter, const)
114+import Prelude hiding
115+ ( concat, map, mapM, takeWhile, take, filter, const, drop, dropWhile
116+ , zipWith
117+ )
62118import Streamly.Internal.Data.Unfold
src/Streamly/Internal/Data/Unfold.hs+129−89
@@ -75,65 +75,78 @@
7575module Streamly.Internal.Data.Unfold
7676 (
7777 -- * Unfold Type
78− Unfold
78+ Step(..)
79+ , Unfold
7980
80− -- * Operations on Input
81− , lmap
82− , lmapM
83− , supply
84− , supplyFirst
85− , supplySecond
86− , discardFirst
87− , discardSecond
88− , swap
89− -- coapply
90− -- comonad
91−
92− -- * Operations on Output
81+ -- * Folding
9382 , fold
9483 -- pipe
9584
9685 -- * Unfolds
97− , fromStream
98− , fromStreamK
99− , fromStreamD
100− , nilM
101− , consM
102− , effect
86+ -- One to one correspondence with
87+ -- "Streamly.Internal.Data.Stream.IsStream.Generate"
88+ -- ** Primitives
10389 , singletonM
10490 , singleton
10591 , identity
106− , const
107− , unfoldrM
108−
109− , fromList
110− , fromListM
111−
112− , fromSVar
113− , fromProducer
92+ , yieldM
93+ , yield
94+ , nilM
95+ , consM
11496
115− -- ** Specialized Generation
97+ -- ** Generators
11698 -- | Generate a monadic stream from a seed.
117− , replicateM
99+ , unfoldrM
118100 , repeatM
119− , iterateM
101+ , replicateM
120102 , fromIndicesM
103+ , iterateM
121104
122105 -- ** Enumerations
106+ -- *** Enumerate Num
107+ , enumerateFromStepNum
108+ , numFrom
109+
110+ -- *** Enumerate Integral
123111 , enumerateFromStepIntegral
124112 , enumerateFromToIntegral
125113 , enumerateFromIntegral
126114
127− , enumerateFromStepNum
128− , numFrom
115+ -- *** Enumerate Fractional
116+ -- | Use 'Num' enumerations for fractional or floating point number
117+ -- enumerations.
129118 , enumerateFromToFractional
130119
131− -- * Transformations
120+ -- ** From Containers
121+ , fromList
122+ , fromListM
123+
124+ , fromStream
125+ , fromStreamK
126+ , fromStreamD
127+
128+ , fromSVar
129+ , fromProducer
130+
131+ -- * Combinators
132+ -- ** Mapping on Input
133+ , lmap
134+ , lmapM
135+ , supply
136+ , supplyFirst
137+ , supplySecond
138+ , discardFirst
139+ , discardSecond
140+ , swap
141+ -- coapply
142+ -- comonad
143+
144+ -- ** Mapping on Output
132145 , map
133146 , mapM
134147 , mapMWithInput
135148
136− -- * Filtering
149+ -- ** Filtering
137150 , takeWhileM
138151 , takeWhile
139152 , take
@@ -143,18 +156,21 @@ module Streamly.Internal.Data.Unfold
143156 , dropWhile
144157 , dropWhileM
145158
146− -- * Zipping
159+ -- ** Zipping
147160 , zipWithM
148161 , zipWith
149162 , teeZipWith
150163
151− -- * Nesting
164+ -- ** Nesting
165+ , cross
166+ , apply
152167 , ConcatState (..)
153168 , many
154169 , concatMapM
170+ , bind
155171 , outerProduct
156172
157− -- * Exceptions
173+ -- ** Exceptions
158174 , gbracket_
159175 , gbracket
160176 , before
@@ -206,7 +222,7 @@ import Prelude
206222-- | Map an action on the input argument of the 'Unfold'.
207223--
208224-- @
209−-- lmapM f = many (singletonM f)
225+-- lmapM f = Unfold.many (Unfold.singletonM f)
210226-- @
211227--
212228-- /Pre-release/
@@ -214,47 +230,54 @@ import Prelude
214230lmapM :: Monad m => (a -> m c) -> Unfold m c b -> Unfold m a b
215231lmapM f (Unfold ustep uinject) = Unfold ustep (f >=> uinject)
216232
217−-- XXX change the signature to the following?
218−-- supply :: a -> Unfold m a b -> Unfold m Void b
219−--
220233-- | Supply the seed to an unfold closing the input end of the unfold.
221234--
235+-- @
236+-- supply a = Unfold.lmap (Prelude.const a)
237+-- @
238+--
222239-- /Pre-release/
223240--
224241{-# INLINE_NORMAL supply #-}
225−supply :: Unfold m a b -> a -> Unfold m Void b
226−supply unf a = lmap (Prelude.const a) unf
242+supply :: a -> Unfold m a b -> Unfold m Void b
243+supply a = lmap (Prelude.const a)
227244
228−-- XXX change the signature to the following?
229−-- supplyFirst :: a -> Unfold m (a, b) c -> Unfold m b c
230−--
231245-- | Supply the first component of the tuple to an unfold that accepts a tuple
232246-- as a seed resulting in a fold that accepts the second component of the tuple
233247-- as a seed.
234248--
249+-- @
250+-- supplyFirst a = Unfold.lmap (a, )
251+-- @
252+--
235253-- /Pre-release/
236254--
237255{-# INLINE_NORMAL supplyFirst #-}
238−supplyFirst :: Unfold m (a, b) c -> a -> Unfold m b c
239−supplyFirst unf a = lmap (a, ) unf
256+supplyFirst :: a -> Unfold m (a, b) c -> Unfold m b c
257+supplyFirst a = lmap (a, )
240258
241−-- XXX change the signature to the following?
242−-- supplySecond :: b -> Unfold m (a, b) c -> Unfold m a c
243−--
244259-- | Supply the second component of the tuple to an unfold that accepts a tuple
245260-- as a seed resulting in a fold that accepts the first component of the tuple
246261-- as a seed.
247262--
263+-- @
264+-- supplySecond b = Unfold.lmap (, b)
265+-- @
266+--
248267-- /Pre-release/
249268--
250269{-# INLINE_NORMAL supplySecond #-}
251−supplySecond :: Unfold m (a, b) c -> b -> Unfold m a c
252−supplySecond unf b = lmap (, b) unf
270+supplySecond :: b -> Unfold m (a, b) c -> Unfold m a c
271+supplySecond b = lmap (, b)
253272
254273-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
255274-- using the argument of the original fold as the second element of tuple and
256275-- discarding the first element of the tuple.
257276--
277+-- @
278+-- discardFirst = Unfold.lmap snd
279+-- @
280+--
258281-- /Pre-release/
259282--
260283{-# INLINE_NORMAL discardFirst #-}
@@ -265,6 +288,10 @@ discardFirst = lmap snd
265288-- using the argument of the original fold as the first element of tuple and
266289-- discarding the second element of the tuple.
267290--
291+-- @
292+-- discardSecond = Unfold.lmap fst
293+-- @
294+--
268295-- /Pre-release/
269296--
270297{-# INLINE_NORMAL discardSecond #-}
@@ -274,6 +301,10 @@ discardSecond = lmap fst
274301-- | Convert an 'Unfold' that accepts a tuple as an argument into an unfold
275302-- that accepts a tuple with elements swapped.
276303--
304+-- @
305+-- swap = Unfold.lmap Tuple.swap
306+-- @
307+--
277308-- /Pre-release/
278309--
279310{-# INLINE_NORMAL swap #-}
@@ -393,7 +424,8 @@ nilM f = Unfold step return
393424 {-# INLINE_LATE step #-}
394425 step x = f x >> return Stop
395426
396−-- | Prepend a monadic single element generator function to an 'Unfold'.
427+-- | Prepend a monadic single element generator function to an 'Unfold'. The
428+-- same seed is used in the action as well as the unfold.
397429--
398430-- /Pre-release/
399431{-# INLINE_NORMAL consM #-}
@@ -414,17 +446,6 @@ consM action unf = Unfold step inject
414446 Skip s -> return $ Skip (Right (Stream step1 s))
415447 Stop -> return Stop
416448
417−-- | Lift a monadic effect into an unfold generating a singleton stream.
418−--
419−{-# INLINE effect #-}
420−effect :: Monad m => m b -> Unfold m Void b
421−effect eff = Unfold step inject
422− where
423− inject _ = return True
424− {-# INLINE_LATE step #-}
425− step True = eff >>= \r -> return $ Yield r False
426− step False = return Stop
427−
428449-- | Convert a list of pure values to a 'Stream'
429450{-# INLINE_LATE fromList #-}
430451fromList :: Monad m => Unfold m [a] a
@@ -514,6 +535,10 @@ iterateM f = Unfold step id
514535-- | @fromIndicesM gen@ generates an infinite stream of values using @gen@
515536-- starting from the seed.
516537--
538+-- @
539+-- fromIndicesM f = Unfold.mapM f $ Unfold.enumerateFrom 0
540+-- @
541+--
517542-- /Pre-release/
518543--
519544{-# INLINE_NORMAL fromIndicesM #-}
@@ -655,9 +680,37 @@ dropWhileM f (Unfold step inject) = Unfold step' inject'
655680dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
656681dropWhile f = dropWhileM (return . f)
657682
658−-------------------------------------------------------------------------------
659−-- Enumeration
660−-------------------------------------------------------------------------------
683+------------------------------------------------------------------------------
684+-- Enumeration of Num
685+------------------------------------------------------------------------------
686+
687+-- | Generate an infinite stream starting from a starting value with increments
688+-- of the given stride. The implementation is numerically stable for floating
689+-- point values.
690+--
691+-- Note 'enumerateFromStepIntegral' is faster for integrals.
692+--
693+-- /Pre-release/
694+--
695+{-# INLINE enumerateFromStepNum #-}
696+enumerateFromStepNum :: (Monad m, Num a) => a -> Unfold m a a
697+enumerateFromStepNum stride = Unfold step return
698+ where
699+ -- XXX This is numerically unstable.
700+ {-# INLINE_LATE step #-}
701+ step !s = return $ (Yield $! s) $! (s + stride)
702+
703+-- | @numFrom = enumerateFromStepNum 1@
704+--
705+-- /Pre-release/
706+--
707+{-# INLINE_NORMAL numFrom #-}
708+numFrom :: (Monad m, Num a) => Unfold m a a
709+numFrom = enumerateFromStepNum 1
710+
711+------------------------------------------------------------------------------
712+-- Enumeration of Integrals
713+------------------------------------------------------------------------------
661714
662715-- | Can be used to enumerate unbounded integrals. This does not check for
663716-- overflow or underflow for bounded integrals.
@@ -674,34 +727,20 @@ enumerateFromStepIntegral = Unfold step inject
674727{-# INLINE enumerateFromToIntegral #-}
675728enumerateFromToIntegral :: (Monad m, Integral a) => a -> Unfold m a a
676729enumerateFromToIntegral to =
677− takeWhile (<= to) $ supplySecond enumerateFromStepIntegral 1
730+ takeWhile (<= to) $ supplySecond 1 enumerateFromStepIntegral
678731
679732{-# INLINE enumerateFromIntegral #-}
680733enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
681734enumerateFromIntegral = enumerateFromToIntegral maxBound
682735
683−-- | Generate an infinite stream starting from the seed with increments of the
684−-- given stride.
685−--
686−-- /Pre-release/
687−--
688−{-# INLINE enumerateFromStepNum #-}
689−enumerateFromStepNum :: (Monad m, Num a) => a -> Unfold m a a
690−enumerateFromStepNum stride = Unfold step return
691− where
692− {-# INLINE_LATE step #-}
693− step !s = return $ (Yield $! s) $! (s + stride)
694−
695−-- | @numFrom = enumerateFromStepNum 1@
696−--
697−-- /Pre-release/
698−--
699−{-# INLINE_NORMAL numFrom #-}
700−numFrom :: (Monad m, Num a) => Unfold m a a
701−numFrom = enumerateFromStepNum 1
736+------------------------------------------------------------------------------
737+-- Enumeration of Fractionals
738+------------------------------------------------------------------------------
702739
703740-- | /Internal/
704741--
742+-- > enumerateFromToFractional to = takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
743+--
705744{-# INLINE_NORMAL enumerateFromToFractional #-}
706745enumerateFromToFractional :: (Monad m, Fractional a, Ord a) => a -> Unfold m a a
707746enumerateFromToFractional to =
@@ -862,6 +901,7 @@ data OuterProductState s1 s2 sy x y =
862901 OuterProductOuter s1 y | OuterProductInner s1 sy s2 x
863902
864903-- XXX this can be written in terms of "cross".
904+-- XXX Remove this in favor of cross?
865905--
866906-- | Create an outer product (vector product or cartesian product) of the
867907-- output streams of two unfolds.
src/Streamly/Internal/Data/Unfold/Type.hs+79−16
@@ -8,19 +8,31 @@
88
99module Streamly.Internal.Data.Unfold.Type
1010 ( Unfold (..)
11+
12+ -- * From values
1113 , singletonM
1214 , singleton
1315 , identity
14− , ConcatState (..)
15− , many
16+ , yieldM
17+ , yield
18+
19+ -- * Transformations
1620 , lmap
1721 , map
18− , const
22+
23+ -- * Nesting
24+ , ConcatState (..)
25+ , many
26+
1927 , apSequence
2028 , apDiscardSnd
2129 , cross
30+ , apply
31+ , bind
32+
2233 , concatMapM
2334 , concatMap
35+
2436 , zipWithM
2537 , zipWith
2638 )
@@ -28,8 +40,8 @@ where
2840
2941#include "inline.hs"
3042
31−import Control.Arrow (Arrow(..))
32−import Control.Category (Category(..))
43+-- import Control.Arrow (Arrow(..))
44+-- import Control.Category (Category(..))
3345import Fusion.Plugin.Types (Fuse(..))
3446import Streamly.Internal.Data.Stream.StreamD.Step (Step(..))
3547
@@ -60,7 +72,7 @@ data Unfold m a b =
6072-- | Map a function on the input argument of the 'Unfold'.
6173--
6274-- @
63−-- lmap f = many (singleton f)
75+-- lmap f = Unfold.many (Unfold.singleton f)
6476-- @
6577--
6678-- /Pre-release/
@@ -93,9 +105,12 @@ instance Functor m => Functor (Unfold m a) where
93105-- Applicative
94106------------------------------------------------------------------------------
95107
96−{-# INLINE const #-}
97−const :: Applicative m => m b -> Unfold m a b
98−const m = Unfold step inject
108+-- | The unfold discards its input and generates a singleton stream using the
109+-- supplied monadic action.
110+--
111+{-# INLINE yieldM #-}
112+yieldM :: Applicative m => m b -> Unfold m a b
113+yieldM m = Unfold step inject
99114
100115 where
101116
@@ -104,6 +119,10 @@ const m = Unfold step inject
104119 step False = (`Yield` True) <$> m
105120 step True = pure Stop
106121
122+-- | Discards the unfold input and always returns the argument of 'yield'.
123+yield :: Applicative m => b -> Unfold m a b
124+yield = yieldM . pure
125+
107126-- | Outer product discarding the first element.
108127--
109128-- /Unimplemented/
@@ -154,9 +173,15 @@ cross (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
154173 Skip s -> Skip (CrossInner a s1 b s)
155174 Stop -> Skip (CrossOuter a s1)
156175
176+apply :: Monad m => Unfold m a (b -> c) -> Unfold m a b -> Unfold m a c
177+apply u1 u2 = fmap (\(a, b) -> a b) (cross u1 u2)
178+
179+{-
157180-- | Example:
158181--
159−-- >>> Stream.toList $ Stream.unfold ((,) <$> Unfold.lmap fst Unfold.fromList <*> Unfold.lmap snd Unfold.fromList) ([1,2],[3,4])
182+-- >>> rlist = Unfold.lmap fst Unfold.fromList
183+-- >>> llist = Unfold.lmap snd Unfold.fromList
184+-- >>> Stream.toList $ Stream.unfold ((,) <$> rlist <*> llist) ([1,2],[3,4])
160185-- [(1,3),(1,4),(2,3),(2,4)]
161186--
162187instance Monad m => Applicative (Unfold m a) where
@@ -164,13 +189,14 @@ instance Monad m => Applicative (Unfold m a) where
164189 pure = const Prelude.. return
165190
166191 {-# INLINE (<*>) #-}
167− u1 <*> u2 = fmap (\(a, b) -> a b) (cross u1 u2)
192+ (<*>) = apply
168193
169194 -- {-# INLINE (*>) #-}
170195 -- (*>) = apSequence
171196
172197 -- {-# INLINE (<*) #-}
173198 -- (<*) = apDiscardSnd
199+-}
174200
175201------------------------------------------------------------------------------
176202-- Monad
@@ -216,15 +242,30 @@ concatMapM f (Unfold step1 inject1) = Unfold step inject
216242concatMap :: Monad m => (b -> Unfold m a c) -> Unfold m a b -> Unfold m a c
217243concatMap f = concatMapM (return Prelude.. f)
218244
245+infixl 1 `bind`
246+
247+{-# INLINE bind #-}
248+bind :: Monad m => Unfold m a b -> (b -> Unfold m a c) -> Unfold m a c
249+bind = flip concatMap
250+
251+{-
219252-- Note: concatMap and Monad instance for unfolds have performance comparable
220253-- to Stream. In fact, concatMap is slower than Stream, that may be some
221254-- optimization issue though.
222255--
256+-- Monad allows an unfold to depend on the output of a previous unfold.
257+-- However, it is probably easier to use streams in such situations.
258+--
223259-- | Example:
224260--
225−-- >>> u = do { x <- Unfold.lmap fst Unfold.fromList; y <- Unfold.lmap snd Unfold.fromList; return (x,y); }
226−-- >>> Stream.toList $ Stream.unfold u ([1,2],[3,4])
227−-- [(1,3),(1,4),(2,3),(2,4)]
261+-- >>> :{
262+-- u = do
263+-- x <- Unfold.enumerateFromToIntegral 4
264+-- y <- Unfold.enumerateFromToIntegral x
265+-- return (x, y)
266+-- :}
267+-- >>> Stream.toList $ Stream.unfold u 1
268+-- [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3),(4,4)]
228269--
229270instance Monad m => Monad (Unfold m a) where
230271 {-# INLINE return #-}
@@ -235,6 +276,7 @@ instance Monad m => Monad (Unfold m a) where
235276
236277 -- {-# INLINE (>>) #-}
237278 -- (>>) = (*>)
279+-}
238280
239281-------------------------------------------------------------------------------
240282-- Category
@@ -258,6 +300,8 @@ singletonM f = Unfold step inject
258300
259301-- | Lift a pure function into an unfold generating a singleton stream.
260302--
303+-- > singleton f = singletonM $ return . f
304+--
261305{-# INLINE singleton #-}
262306singleton :: Monad m => (a -> b) -> Unfold m a b
263307singleton f = singletonM $ return Prelude.. f
@@ -265,11 +309,11 @@ singleton f = singletonM $ return Prelude.. f
265309-- | Identity unfold. Generates a singleton stream with the seed as the only
266310-- element in the stream.
267311--
268−-- > identity = singletonM return
312+-- > identity = singleton Prelude.id
269313--
270314{-# INLINE identity #-}
271315identity :: Monad m => Unfold m a a
272−identity = singletonM return
316+identity = singleton Prelude.id
273317
274318{-# ANN type ConcatState Fuse #-}
275319data ConcatState s1 s2 = ConcatOuter s1 | ConcatInner s1 s2
@@ -306,17 +350,25 @@ many (Unfold step1 inject1) (Unfold step2 inject2) = Unfold step inject
306350 Skip s -> Skip (ConcatInner ost s)
307351 Stop -> Skip (ConcatOuter ost)
308352
353+{-
354+-- XXX There are multiple possible ways to combine the unfolds, "many" appends
355+-- them, we could also have other variants of "many" e.g. manyInterleave.
356+-- Should we even have a category instance or just use these functions
357+-- directly?
358+--
309359instance Monad m => Category (Unfold m) where
310360 {-# INLINE id #-}
311361 id = identity
312362
313363 {-# INLINE (.) #-}
314364 (.) = flip many
365+-}
315366
316367-------------------------------------------------------------------------------
317368-- Arrow
318369-------------------------------------------------------------------------------
319370
371+-- | Stops as soon as any of the unfolds stops.
320372{-# INLINE_NORMAL zipWithM #-}
321373zipWithM :: Monad m
322374 => (a -> b -> m c) -> Unfold m x a -> Unfold m y b -> Unfold m (x, y) c
@@ -364,6 +416,16 @@ zipWith :: Monad m
364416 => (a -> b -> c) -> Unfold m x a -> Unfold m y b -> Unfold m (x, y) c
365417zipWith f = zipWithM (\a b -> return (f a b))
366418
419+{-
420+-- XXX There are multiple ways of combining the outputs of two unfolds, we
421+-- could zip, merge, append and more. What is the preferred way for Arrow
422+-- instance? Should we even have an arrow instance or just use these functions
423+-- directly?
424+--
425+-- | '***' is a zip like operation, in fact it is the same as @Unfold.zipWith
426+-- (,)@, '&&&' is a tee like operation i.e. distributes the input to both the
427+-- unfolds and then zips the output.
428+--
367429{-# ANN module "HLint: ignore Use zip" #-}
368430instance Monad m => Arrow (Unfold m) where
369431 {-# INLINE arr #-}
@@ -371,3 +433,4 @@ instance Monad m => Arrow (Unfold m) where
371433
372434 {-# INLINE (***) #-}
373435 (***) = zipWith (,)
436+-}
src/Streamly/Internal/FileSystem/Handle.hs+2−2
@@ -262,7 +262,7 @@ getBytes = toBytes stdin
262262-- @since 0.7.0
263263{-# INLINE readChunks #-}
264264readChunks :: MonadIO m => Unfold m Handle (Array Word8)
265−readChunks = UF.supplyFirst readChunksWithBufferOf defaultChunkSize
265+readChunks = UF.supplyFirst defaultChunkSize readChunksWithBufferOf
266266
267267-------------------------------------------------------------------------------
268268-- Read File to Stream
@@ -299,7 +299,7 @@ toBytesWithBufferOf chunkSize h = AS.concat $ toChunksWithBufferOf chunkSize h
299299-- @since 0.7.0
300300{-# INLINE read #-}
301301read :: MonadIO m => Unfold m Handle Word8
302−read = UF.supplyFirst readWithBufferOf defaultChunkSize
302+read = UF.supplyFirst defaultChunkSize readWithBufferOf
303303
304304-- | Generate a byte stream from a file 'Handle'.
305305--
src/Streamly/Internal/Network/Inet/TCP.hs+3−3
@@ -161,7 +161,7 @@ acceptOnAddr = acceptOnAddrWith []
161161acceptOnPortWith :: MonadIO m
162162 => [(SocketOption, Int)]
163163 -> Unfold m PortNumber Socket
164−acceptOnPortWith opts = UF.supplyFirst (acceptOnAddrWith opts) (0,0,0,0)
164+acceptOnPortWith opts = UF.supplyFirst (0,0,0,0) (acceptOnAddrWith opts)
165165
166166-- | Like 'acceptOnAddr' but binds on the IPv4 address @0.0.0.0@ i.e. on all
167167-- IPv4 addresses/interfaces of the machine and listens for TCP connections on
@@ -172,7 +172,7 @@ acceptOnPortWith opts = UF.supplyFirst (acceptOnAddrWith opts) (0,0,0,0)
172172-- @since 0.7.0
173173{-# INLINE acceptOnPort #-}
174174acceptOnPort :: MonadIO m => Unfold m PortNumber Socket
175−acceptOnPort = UF.supplyFirst acceptOnAddr (0,0,0,0)
175+acceptOnPort = UF.supplyFirst (0,0,0,0) acceptOnAddr
176176
177177-- | Like 'acceptOnAddr' but binds on the localhost IPv4 address @127.0.0.1@.
178178-- The server can only be accessed from the local host, it cannot be accessed
@@ -183,7 +183,7 @@ acceptOnPort = UF.supplyFirst acceptOnAddr (0,0,0,0)
183183-- @since 0.7.0
184184{-# INLINE acceptOnPortLocal #-}
185185acceptOnPortLocal :: MonadIO m => Unfold m PortNumber Socket
186−acceptOnPortLocal = UF.supplyFirst acceptOnAddr (127,0,0,1)
186+acceptOnPortLocal = UF.supplyFirst (127,0,0,1) acceptOnAddr
187187
188188-------------------------------------------------------------------------------
189189-- Accept (streams)
src/Streamly/Internal/Network/Socket.hs+2−2
@@ -387,7 +387,7 @@ readChunksWithBufferOf = Unfold step return
387387-- @since 0.7.0
388388{-# INLINE readChunks #-}
389389readChunks :: MonadIO m => Unfold m Socket (Array Word8)
390−readChunks = UF.supplyFirst readChunksWithBufferOf A.defaultChunkSize
390+readChunks = UF.supplyFirst A.defaultChunkSize readChunksWithBufferOf
391391
392392-------------------------------------------------------------------------------
393393-- Read File to Stream
@@ -434,7 +434,7 @@ readWithBufferOf = UF.many readChunksWithBufferOf A.read
434434-- @since 0.7.0
435435{-# INLINE read #-}
436436read :: MonadIO m => Unfold m Socket Word8
437−read = UF.supplyFirst readWithBufferOf A.defaultChunkSize
437+read = UF.supplyFirst A.defaultChunkSize readWithBufferOf
438438
439439-------------------------------------------------------------------------------
440440-- Writing
test/Streamly/Test/Data/Unfold.hs+4−10
@@ -72,17 +72,17 @@ lmapM =
7272
7373supply :: Bool
7474supply =
75− let unf = UF.supply (UF.singleton id) 1
75+ let unf = UF.supply 1 (UF.singleton id)
7676 in testUnfold unf undefined ([1] :: [Int])
7777
7878supplyFirst :: Bool
7979supplyFirst =
80− let unf = UF.supplyFirst (UF.singleton id) 1
80+ let unf = UF.supplyFirst 1 (UF.singleton id)
8181 in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)])
8282
8383supplySecond :: Bool
8484supplySecond =
85− let unf = UF.supplySecond (UF.singleton id) 1
85+ let unf = UF.supplySecond 1 (UF.singleton id)
8686 in testUnfold unf 2 ([(2, 1)] :: [(Int, Int)])
8787
8888discardFirst :: Bool
@@ -134,11 +134,6 @@ consM =
134134 unf = cns $ cns $ UF.nilM $ \a -> modify (+ a)
135135 in testUnfoldMD unf 1 0 3 [1, 2]
136136
137−effect :: Bool
138−effect =
139− let unf = UF.effect (modify (+ 1) >> get)
140− in testUnfoldMD unf undefined 0 1 [1]
141−
142137singletonM :: Bool
143138singletonM =
144139 let unf = UF.singletonM (\a -> modify (+ a) >> get)
@@ -146,7 +141,7 @@ singletonM =
146141
147142const :: Bool
148143const =
149− let unf = UF.const (modify (+ 1) >> get)
144+ let unf = UF.yieldM (modify (+ 1) >> get)
150145 in testUnfoldMD unf (0 :: Int) 0 1 [1]
151146
152147unfoldrM :: Property
@@ -380,7 +375,6 @@ testGeneration =
380375 prop "fromStreamD" fromStreamD
381376 prop "nilM" nilM
382377 prop "consM" consM
383− prop "effect" effect
384378 prop "singletonM" singletonM
385379 -- prop "singleton" singleton
386380 -- prop "identity" identity
test/Streamly/Test/Prelude/Serial.hs+1−1
@@ -457,7 +457,7 @@ unfold0 :: Property
457457unfold0 = monadicIO $ do
458458 a <- pick $ choose (0, max_length `div` 2)
459459 b <- pick $ choose (0, max_length)
460− let unf = UF.supply (UF.enumerateFromToIntegral b) a
460+ let unf = UF.supply a (UF.enumerateFromToIntegral b)
461461 ls <- S.toList $ IS.unfold0 unf
462462 return $ ls == [a..b]
463463
test/lib/Streamly/Test/Prelude/Common.hs+1−1
@@ -1202,7 +1202,7 @@ transformCombineOpsCommon constr desc eq t = do
12021202 forAll (choose (0, 100)) $ \n ->
12031203 transform (concatMap (const [1..n]))
12041204 t (S.unfoldMany (UF.lmap (const undefined)
1205− $ UF.supply UF.fromList [1..n]))
1205+ $ UF.supply [1..n] UF.fromList))
12061206
12071207toListFL :: Monad m => FL.Fold m a [a]
12081208toListFL = FL.toList