1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving#-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE StandaloneDeriving #-}
7{-# LANGUAGE UndecidableInstances #-} -- XXX
10-- Module : Streamly.Streams
11-- Copyright : (c) 2017 Harendra Kumar
14-- Maintainer : harendra.kumar@gmail.com
15-- Stability : experimental
19module Streamly.Streams
75 -- * Sum Style Composition
87import Control.Applicative (Alternative (..), liftA2)
88import Control.Monad (MonadPlus(..), ap)
89import Control.Monad.Base (MonadBase (..))
90import Control.Monad.Catch (MonadThrow)
91import Control.Monad.Error.Class (MonadError(..))
92import Control.Monad.IO.Class (MonadIO(..))
93import Control.Monad.Reader.Class (MonadReader(..))
94import Control.Monad.State.Class (MonadState(..))
95import Control.Monad.Trans.Class (MonadTrans)
96import Data.Semigroup (Semigroup(..))
97import Prelude hiding (drop, take, zipWith)
100------------------------------------------------------------------------------
101-- Types that can behave as a Stream
102------------------------------------------------------------------------------
104-- | Class of types that can represent a stream of elements of some type 'a' in
106class Streaming t where
107 toStream :: t m a -> Stream m a
108 fromStream :: Stream m a -> t m a
110------------------------------------------------------------------------------
111-- Constructing a stream
112------------------------------------------------------------------------------
114-- | Add an element a the head of a stream.
115cons :: (Streaming t) => a -> t m a -> t m a
116cons a r = fromStream $ scons a (Just (toStream r))
119nil :: Streaming t => t m a
120nil = fromStream $ snil
122-- | Build a stream from its church encoding. The function passed maps
123-- directly to the underlying representation of the stream type. The second
124-- parameter to the function is the "yield" function yielding a value and the
125-- remaining stream if any otherwise 'Nothing'. The third parameter is to
126-- represent an "empty" stream.
127streamBuild :: Streaming t
128 => (forall r. Maybe (SVar m a)
129 -> (a -> Maybe (t m a) -> m r)
133streamBuild k = fromStream $ Stream $ \sv stp yld ->
134 let yield a Nothing = yld a Nothing
135 yield a (Just r) = yld a (Just (toStream r))
138-- | Build a singleton stream from a callback function.
139fromCallback :: (Streaming t) => (forall r. (a -> m r) -> m r) -> t m a
140fromCallback k = fromStream $ Stream $ \_ _ yld -> k (\a -> yld a Nothing)
142-- | Read an SVar to get a stream.
143fromSVar :: (MonadAsync m, Streaming t) => SVar m a -> t m a
144fromSVar sv = fromStream $ fromStreamVar sv
146------------------------------------------------------------------------------
147-- Destroying a stream
148------------------------------------------------------------------------------
150-- | Fold a stream using its church encoding. The second argument is the "step"
151-- function consuming an element and the remaining stream, if any. The third
152-- argument is for consuming an "empty" stream that yields nothing.
153streamFold :: Streaming t
154 => Maybe (SVar m a) -> (a -> Maybe (t m a) -> m r) -> m r -> t m a -> m r
155streamFold sv step blank m =
156 let yield a Nothing = step a Nothing
157 yield a (Just x) = step a (Just (fromStream x))
158 in (runStream (toStream m)) sv blank yield
160-- | Run a streaming composition, discard the results.
161runStreaming :: (Monad m, Streaming t) => t m a -> m ()
162runStreaming m = go (toStream m)
166 yield _ Nothing = stop
167 yield _ (Just x) = go x
168 in (runStream m1) Nothing stop yield
170-- | Write a stream to an 'SVar' in a non-blocking manner. The stream can then
171-- be read back from the SVar using 'fromSVar'.
172toSVar :: (Streaming t, MonadAsync m) => SVar m a -> t m a -> m ()
173toSVar sv m = toStreamVar sv (toStream m)
175------------------------------------------------------------------------------
177------------------------------------------------------------------------------
179-- XXX Get rid of this?
180-- | Make a stream asynchronous, triggers the computation and returns a stream
181-- in the underlying monad representing the output generated by the original
182-- computation. The returned action is exhaustible and must be drained once. If
183-- not drained fully we may have a thread blocked forever and once exhausted it
184-- will always return 'empty'.
186async :: (Streaming t, MonadAsync m) => t m a -> m (t m a)
188 sv <- newStreamVar1 (SVarStyle Disjunction LIFO) (toStream m)
191------------------------------------------------------------------------------
193------------------------------------------------------------------------------
195-- | The 'Monad' instance of 'StreamT' runs the /monadic continuation/ for each
196-- element of the stream, serially.
199-- main = 'runStreamT' $ do
200-- x <- return 1 \<\> return 2
208-- 'StreamT' nests streams serially in a depth first manner.
211-- main = 'runStreamT' $ do
212-- x <- return 1 \<\> return 2
213-- y <- return 3 \<\> return 4
214-- liftIO $ print (x, y)
223-- This behavior is exactly like a list transformer. We call the monadic code
224-- being run for each element of the stream a monadic continuation. In
225-- imperative paradigm we can think of this composition as nested @for@ loops
226-- and the monadic continuation is the body of the loop. The loop iterates for
227-- all elements of the stream.
229newtype StreamT m a = StreamT {getStreamT :: Stream m a}
230 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
232deriving instance MonadAsync m => Alternative (StreamT m)
233deriving instance MonadAsync m => MonadPlus (StreamT m)
234deriving instance (MonadBase b m, Monad m) => MonadBase b (StreamT m)
235deriving instance MonadError e m => MonadError e (StreamT m)
236deriving instance MonadReader r m => MonadReader r (StreamT m)
237deriving instance MonadState s m => MonadState s (StreamT m)
239instance Streaming StreamT where
240 toStream = getStreamT
243-- XXX The Functor/Applicative/Num instances for all the types are exactly the
244-- same, how can we reduce this boilerplate (use TH)? We cannot derive them
245-- from a single base type because they depend on the Monad instance which is
246-- different for each type.
248------------------------------------------------------------------------------
250------------------------------------------------------------------------------
252instance Monad m => Monad (StreamT m) where
254 (StreamT (Stream m)) >>= f = StreamT $ Stream $ \_ stp yld ->
255 let run x = (runStream x) Nothing stp yld
256 yield a Nothing = run $ getStreamT (f a)
257 yield a (Just r) = run $ getStreamT (f a)
258 <> getStreamT (StreamT r >>= f)
259 in m Nothing stp yield
261------------------------------------------------------------------------------
263------------------------------------------------------------------------------
265instance Monad m => Applicative (StreamT m) where
266 pure a = StreamT $ scons a Nothing
269------------------------------------------------------------------------------
271------------------------------------------------------------------------------
273instance Monad m => Functor (StreamT m) where
274 fmap f (StreamT (Stream m)) = StreamT $ Stream $ \_ stp yld ->
275 let yield a Nothing = yld (f a) Nothing
276 yield a (Just r) = yld (f a)
277 (Just (getStreamT (fmap f (StreamT r))))
278 in m Nothing stp yield
280------------------------------------------------------------------------------
282------------------------------------------------------------------------------
284instance (Monad m, Num a) => Num (StreamT m a) where
285 fromInteger n = pure (fromInteger n)
295instance (Monad m, Fractional a) => Fractional (StreamT m a) where
296 fromRational n = pure (fromRational n)
302instance (Monad m, Floating a) => Floating (StreamT m a) where
322 logBase = liftA2 logBase
324------------------------------------------------------------------------------
326------------------------------------------------------------------------------
328-- | Like 'StreamT' but different in nesting behavior. It fairly interleaves
329-- the iterations of the inner and the outer loop, nesting loops in a breadth
334-- main = 'runInterleavedT' $ do
335-- x <- return 1 \<\> return 2
336-- y <- return 3 \<\> return 4
337-- liftIO $ print (x, y)
346newtype InterleavedT m a = InterleavedT {getInterleavedT :: Stream m a}
347 deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
349deriving instance MonadAsync m => Alternative (InterleavedT m)
350deriving instance MonadAsync m => MonadPlus (InterleavedT m)
351deriving instance (MonadBase b m, Monad m) => MonadBase b (InterleavedT m)
352deriving instance MonadError e m => MonadError e (InterleavedT m)
353deriving instance MonadReader r m => MonadReader r (InterleavedT m)
354deriving instance MonadState s m => MonadState s (InterleavedT m)
356instance Streaming InterleavedT where
357 toStream = getInterleavedT
358 fromStream = InterleavedT
360instance Monad m => Monad (InterleavedT m) where
362 (InterleavedT (Stream m)) >>= f = InterleavedT $ Stream $ \_ stp yld ->
363 let run x = (runStream x) Nothing stp yld
364 yield a Nothing = run $ getInterleavedT (f a)
365 yield a (Just r) = run $ getInterleavedT (f a)
367 getInterleavedT (InterleavedT r >>= f)
368 in m Nothing stp yield
370------------------------------------------------------------------------------
372------------------------------------------------------------------------------
374instance Monad m => Applicative (InterleavedT m) where
375 pure a = InterleavedT $ scons a Nothing
378------------------------------------------------------------------------------
380------------------------------------------------------------------------------
382instance Monad m => Functor (InterleavedT m) where
383 fmap f (InterleavedT (Stream m)) = InterleavedT $ Stream $ \_ stp yld ->
384 let yield a Nothing = yld (f a) Nothing
386 yld (f a) (Just (getInterleavedT (fmap f (InterleavedT r))))
387 in m Nothing stp yield
389------------------------------------------------------------------------------
391------------------------------------------------------------------------------
393instance (Monad m, Num a) => Num (InterleavedT m a) where
394 fromInteger n = pure (fromInteger n)
404instance (Monad m, Fractional a) => Fractional (InterleavedT m a) where
405 fromRational n = pure (fromRational n)
411instance (Monad m, Floating a) => Floating (InterleavedT m a) where
431 logBase = liftA2 logBase
433------------------------------------------------------------------------------
435------------------------------------------------------------------------------
437-- | Like 'StreamT' but /may/ run each iteration concurrently using demand
438-- driven concurrency. More concurrent iterations are started only if the
439-- previous iterations are not able to produce enough output for the consumer.
443-- import Control.Concurrent
445-- main = 'runAsyncT' $ do
446-- n <- return 3 \<\> return 2 \<\> return 1
448-- threadDelay (n * 1000000)
449-- myThreadId >>= \\tid -> putStrLn (show tid ++ ": Delay " ++ show n)
452-- ThreadId 40: Delay 1
453-- ThreadId 39: Delay 2
454-- ThreadId 38: Delay 3
457-- All iterations may run in the same thread if they do not block.
458newtype AsyncT m a = AsyncT {getAsyncT :: Stream m a}
459 deriving (Semigroup, Monoid, MonadTrans)
461deriving instance MonadAsync m => Alternative (AsyncT m)
462deriving instance MonadAsync m => MonadPlus (AsyncT m)
463deriving instance MonadAsync m => MonadIO (AsyncT m)
464deriving instance MonadAsync m => MonadThrow (AsyncT m)
465deriving instance (MonadBase b m, MonadAsync m) => MonadBase b (AsyncT m)
466deriving instance (MonadError e m, MonadAsync m) => MonadError e (AsyncT m)
467deriving instance (MonadReader r m, MonadAsync m) => MonadReader r (AsyncT m)
468deriving instance (MonadState s m, MonadAsync m) => MonadState s (AsyncT m)
470instance Streaming AsyncT where
474{-# INLINE parbind #-}
476 :: (forall c. Stream m c -> Stream m c -> Stream m c)
480parbind par m f = go m
483 Stream $ \ctx stp yld ->
484 let run x = (runStream x) ctx stp yld
485 yield a Nothing = run $ f a
486 yield a (Just r) = run $ f a `par` (go r)
487 in g Nothing stp yield
489instance MonadAsync m => Monad (AsyncT m) where
491 (AsyncT m) >>= f = AsyncT $ parbind par m g
492 where g x = getAsyncT (f x)
493 par = joinStreamVar2 (SVarStyle Conjunction LIFO)
495------------------------------------------------------------------------------
497------------------------------------------------------------------------------
499instance MonadAsync m => Applicative (AsyncT m) where
500 pure a = AsyncT $ scons a Nothing
503------------------------------------------------------------------------------
505------------------------------------------------------------------------------
507instance Monad m => Functor (AsyncT m) where
508 fmap f (AsyncT (Stream m)) = AsyncT $ Stream $ \_ stp yld ->
509 let yield a Nothing = yld (f a) Nothing
510 yield a (Just r) = yld (f a) (Just (getAsyncT (fmap f (AsyncT r))))
511 in m Nothing stp yield
513------------------------------------------------------------------------------
515------------------------------------------------------------------------------
517instance (MonadAsync m, Num a) => Num (AsyncT m a) where
518 fromInteger n = pure (fromInteger n)
528instance (MonadAsync m, Fractional a) => Fractional (AsyncT m a) where
529 fromRational n = pure (fromRational n)
535instance (MonadAsync m, Floating a) => Floating (AsyncT m a) where
555 logBase = liftA2 logBase
557------------------------------------------------------------------------------
559------------------------------------------------------------------------------
561-- | Like 'StreamT' but runs /all/ iterations fairly concurrently using a round
566-- import Control.Concurrent
568-- main = 'runParallelT' $ do
569-- n <- return 3 \<\> return 2 \<\> return 1
571-- threadDelay (n * 1000000)
572-- myThreadId >>= \\tid -> putStrLn (show tid ++ ": Delay " ++ show n)
575-- ThreadId 40: Delay 1
576-- ThreadId 39: Delay 2
577-- ThreadId 38: Delay 3
580-- Unlike 'AsyncT' all iterations are guaranteed to run fairly concurrently,
582newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
583 deriving (Semigroup, Monoid, MonadTrans)
585deriving instance MonadAsync m => Alternative (ParallelT m)
586deriving instance MonadAsync m => MonadPlus (ParallelT m)
587deriving instance MonadAsync m => MonadIO (ParallelT m)
588deriving instance MonadAsync m => MonadThrow (ParallelT m)
589deriving instance (MonadBase b m, MonadAsync m) => MonadBase b (ParallelT m)
590deriving instance (MonadError e m, MonadAsync m) => MonadError e (ParallelT m)
591deriving instance (MonadReader r m, MonadAsync m) => MonadReader r (ParallelT m)
592deriving instance (MonadState s m, MonadAsync m) => MonadState s (ParallelT m)
594instance Streaming ParallelT where
595 toStream = getParallelT
596 fromStream = ParallelT
598instance MonadAsync m => Monad (ParallelT m) where
600 (ParallelT m) >>= f = ParallelT $ parbind par m g
601 where g x = getParallelT (f x)
602 par = joinStreamVar2 (SVarStyle Conjunction FIFO)
604------------------------------------------------------------------------------
606------------------------------------------------------------------------------
608instance MonadAsync m => Applicative (ParallelT m) where
609 pure a = ParallelT $ scons a Nothing
612------------------------------------------------------------------------------
614------------------------------------------------------------------------------
616instance Monad m => Functor (ParallelT m) where
617 fmap f (ParallelT (Stream m)) = ParallelT $ Stream $ \_ stp yld ->
618 let yield a Nothing = yld (f a) Nothing
619 yield a (Just r) = yld (f a)
620 (Just (getParallelT (fmap f (ParallelT r))))
621 in m Nothing stp yield
623------------------------------------------------------------------------------
625------------------------------------------------------------------------------
627instance (MonadAsync m, Num a) => Num (ParallelT m a) where
628 fromInteger n = pure (fromInteger n)
638instance (MonadAsync m, Fractional a) => Fractional (ParallelT m a) where
639 fromRational n = pure (fromRational n)
645instance (MonadAsync m, Floating a) => Floating (ParallelT m a) where
665 logBase = liftA2 logBase
667------------------------------------------------------------------------------
668-- Serially Zipping Streams
669------------------------------------------------------------------------------
671-- | Zip two streams serially using a pure zipping function.
672zipWith :: Streaming t => (a -> b -> c) -> t m a -> t m b -> t m c
673zipWith f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
675 go mx my = Stream $ \_ stp yld -> do
677 let yield2 b Nothing = yld (f a b) Nothing
678 yield2 b (Just rb) = yld (f a b) (Just (go ra rb))
679 in (runStream my) Nothing stp yield2
680 let yield1 a Nothing = merge a snil
681 yield1 a (Just ra) = merge a ra
682 (runStream mx) Nothing stp yield1
684-- | 'ZipStream' zips serially i.e. it produces one element from each stream
685-- serially and then zips the two elements. Note, for convenience we have used
686-- the 'zipping' combinator in the following example instead of using a type
690-- main = (toList . 'zipping' $ (,) \<$\> s1 \<*\> s2) >>= print
691-- where s1 = pure 1 <> pure 2
692-- s2 = pure 3 <> pure 4
698-- This applicative operation can be seen as the zipping equivalent of
699-- interleaving with '<=>'.
700newtype ZipStream m a = ZipStream {getZipStream :: Stream m a}
701 deriving (Semigroup, Monoid)
703deriving instance MonadAsync m => Alternative (ZipStream m)
705instance Monad m => Functor (ZipStream m) where
706 fmap f (ZipStream (Stream m)) = ZipStream $ Stream $ \_ stp yld ->
707 let yield a Nothing = yld (f a) Nothing
708 yield a (Just r) = yld (f a)
709 (Just (getZipStream (fmap f (ZipStream r))))
710 in m Nothing stp yield
712instance Monad m => Applicative (ZipStream m) where
713 pure a = ZipStream $ scons a Nothing
716instance Streaming ZipStream where
717 toStream = getZipStream
718 fromStream = ZipStream
720instance (Monad m, Num a) => Num (ZipStream m a) where
721 fromInteger n = pure (fromInteger n)
731instance (Monad m, Fractional a) => Fractional (ZipStream m a) where
732 fromRational n = pure (fromRational n)
738instance (Monad m, Floating a) => Floating (ZipStream m a) where
758 logBase = liftA2 logBase
760------------------------------------------------------------------------------
761-- Parallely Zipping Streams
762------------------------------------------------------------------------------
764-- | Zip two streams asyncly (i.e. both the elements being zipped are generated
765-- concurrently) using a pure zipping function.
766zipAsyncWith :: (Streaming t, MonadAsync m)
767 => (a -> b -> c) -> t m a -> t m b -> t m c
768zipAsyncWith f m1 m2 = fromStream $ Stream $ \_ stp yld -> do
771 (runStream (toStream (zipWith f ma mb))) Nothing stp yld
773-- | Like 'ZipStream' but zips in parallel, it generates both the elements to
774-- be zipped concurrently.
777-- main = (toList . 'zippingAsync' $ (,) \<$\> s1 \<*\> s2) >>= print
778-- where s1 = pure 1 <> pure 2
779-- s2 = pure 3 <> pure 4
785-- This applicative operation can be seen as the zipping equivalent of
786-- parallel composition with '<|>'.
787newtype ZipAsync m a = ZipAsync {getZipAsync :: Stream m a}
788 deriving (Semigroup, Monoid)
790deriving instance MonadAsync m => Alternative (ZipAsync m)
792instance Monad m => Functor (ZipAsync m) where
793 fmap f (ZipAsync (Stream m)) = ZipAsync $ Stream $ \_ stp yld ->
794 let yield a Nothing = yld (f a) Nothing
795 yield a (Just r) = yld (f a)
796 (Just (getZipAsync (fmap f (ZipAsync r))))
797 in m Nothing stp yield
799instance MonadAsync m => Applicative (ZipAsync m) where
800 pure a = ZipAsync $ scons a Nothing
801 (<*>) = zipAsyncWith id
803instance Streaming ZipAsync where
804 toStream = getZipAsync
805 fromStream = ZipAsync
807instance (MonadAsync m, Num a) => Num (ZipAsync m a) where
808 fromInteger n = pure (fromInteger n)
818instance (MonadAsync m, Fractional a) => Fractional (ZipAsync m a) where
819 fromRational n = pure (fromRational n)
825instance (MonadAsync m, Floating a) => Floating (ZipAsync m a) where
845 logBase = liftA2 logBase
847-------------------------------------------------------------------------------
848-- Type adapting combinators
849-------------------------------------------------------------------------------
851-- | Adapt one streaming type to another.
852adapt :: (Streaming t1, Streaming t2) => t1 m a -> t2 m a
853adapt = fromStream . toStream
855-- | Interpret an ambiguously typed stream as 'StreamT'.
856serially :: StreamT m a -> StreamT m a
859-- | Interpret an ambiguously typed stream as 'InterleavedT'.
860interleaving :: InterleavedT m a -> InterleavedT m a
863-- | Interpret an ambiguously typed stream as 'AsyncT'.
864asyncly :: AsyncT m a -> AsyncT m a
867-- | Interpret an ambiguously typed stream as 'ParallelT'.
868parallely :: ParallelT m a -> ParallelT m a
871-- | Interpret an ambiguously typed stream as 'ZipStream'.
872zipping :: ZipStream m a -> ZipStream m a
875-- | Interpret an ambiguously typed stream as 'ZipAsync'.
876zippingAsync :: ZipAsync m a -> ZipAsync m a
879-------------------------------------------------------------------------------
880-- Running Streams, convenience functions specialized to types
881-------------------------------------------------------------------------------
883-- | Same as @runStreaming . serially@.
884runStreamT :: Monad m => StreamT m a -> m ()
885runStreamT = runStreaming
887-- | Same as @runStreaming . interleaving@.
888runInterleavedT :: Monad m => InterleavedT m a -> m ()
889runInterleavedT = runStreaming
891-- | Same as @runStreaming . asyncly@.
892runAsyncT :: Monad m => AsyncT m a -> m ()
893runAsyncT = runStreaming
895-- | Same as @runStreaming . parallely@.
896runParallelT :: Monad m => ParallelT m a -> m ()
897runParallelT = runStreaming
899-- | Same as @runStreaming . zipping@.
900runZipStream :: Monad m => ZipStream m a -> m ()
901runZipStream = runStreaming
903-- | Same as @runStreaming . zippingAsync@.
904runZipAsync :: Monad m => ZipAsync m a -> m ()
905runZipAsync = runStreaming
907------------------------------------------------------------------------------
908-- Sum Style Composition
909------------------------------------------------------------------------------
913-- | Sequential interleaved composition, in contrast to '<>' this operator
914-- fairly interleaves two streams instead of appending them; yielding one
915-- element from each stream alternately.
918-- main = ('toList' . 'serially' $ (return 1 <> return 2) \<=\> (return 3 <> return 4)) >>= print
924-- This operator corresponds to the 'InterleavedT' style. Unlike '<>', this
925-- operator cannot be used to fold infinite containers since that might
926-- accumulate too many partially drained streams. To be clear, it can combine
927-- infinite streams but not infinite number of streams.
929(<=>) :: Streaming t => t m a -> t m a -> t m a
930m1 <=> m2 = fromStream $ interleave (toStream m1) (toStream m2)
932-- | Demand driven concurrent composition. In contrast to '<|>' this operator
933-- concurrently "merges" streams in a left biased manner rather than fairly
934-- interleaving them. It keeps yielding from the stream on the left as long as
935-- it can. If the left stream blocks or cannot keep up with the pace of the
936-- consumer it can concurrently yield from the stream on the right in parallel.
939-- main = ('toList' . 'serially' $ (return 1 <> return 2) \<| (return 3 <> return 4)) >>= print
945-- Unlike '<|>' it can be used to fold infinite containers of streams. This
946-- operator corresponds to the 'AsyncT' type for product style composition.
949(<|) :: (Streaming t, MonadAsync m) => t m a -> t m a -> t m a
950m1 <| m2 = fromStream $ parLeft (toStream m1) (toStream m2)
952------------------------------------------------------------------------------
954------------------------------------------------------------------------------
957-- These utilities are designed to pass the first argument as one of the sum
958-- style composition operators (i.e. '<>', '<=>', '<|', '<|>') to conveniently
959-- fold a container using any style of stream composition.
961-- | Like the 'Prelude' 'fold' but allows you to specify a binary sum style
962-- stream composition operator to fold a container of streams.
964-- @foldWith (<>) $ map return [1..3]@
965{-# INLINABLE foldWith #-}
966foldWith :: (Streaming t, Foldable f)
967 => (t m a -> t m a -> t m a) -> f (t m a) -> t m a
968foldWith f = foldr f nil
970-- | Like 'foldMap' but allows you to specify a binary sum style composition
971-- operator to fold a container of streams. Maps a monadic streaming action on
972-- the container before folding it.
974-- @foldMapWith (<>) return [1..3]@
975{-# INLINABLE foldMapWith #-}
976foldMapWith :: (Streaming t, Foldable f)
977 => (t m b -> t m b -> t m b) -> (a -> t m b) -> f a -> t m b
978foldMapWith f g = foldr (f . g) nil
980-- | Like 'foldMapWith' but with the last two arguments reversed i.e. the
981-- monadic streaming function is the last argument.
982{-# INLINABLE forEachWith #-}
983forEachWith :: (Streaming t, Foldable f)
984 => (t m b -> t m b -> t m b) -> f a -> (a -> t m b) -> t m b
985forEachWith f xs g = foldr (f . g) nil xs
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list