HORIZON HASKELLDocslts/ghc-10.0.xfc4e5982026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · fc4e598 · 2026-10-11

Modulestreamly-0.11.1Haskell2010

Streamly.Internal.Data.Fold.Prelude

  • 3 types
  • 29 values
  • Packagestreamly-0.11.1
  • Exports32
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceType.hs

Channel

17 declarations
valueboundThreads :: Bool -> Config -> Config
#

Spawn bound threads (i.e., spawn threads using forkOS instead of forkIO). The default value is False.

Currently, this only takes effect only for concurrent folds.

valuecheckFoldStatus :: MonadAsync m => Channel m a b -> m (Maybe b)
#

Poll for events sent by the fold worker to the fold driver. The fold consumer can send a Stop event or an exception. When a Stop is received this function returns True. If an exception is recieved then it throws the exception.

valuedefaultConfig :: Config
#

The fields prefixed by an _ are not to be accessed or updated directly but via smart accessor APIs. Use get/set routines instead of directly accessing the Config fields

valueinspect :: Bool -> Config -> Config
#

Print debug information about the Channel when the stream ends. When the stream does not end normally, the channel debug information is printed when the channel is garbage collected. If you are expecting but not seeing the debug info try adding a performMajorGC before the program ends.

valuemaxBuffer :: Int -> Config -> Config
#

Specify the maximum size of the buffer for storing the results from concurrent computations. If the buffer becomes full we stop spawning more concurrent tasks until there is space in the buffer. A value of 0 resets the buffer size to default, a negative value means there is no limit. The default value is 1500.

CAUTION! using an unbounded maxBuffer value (i.e. a negative value) coupled with an unbounded maxThreads value is a recipe for disaster in presence of infinite streams, or very large streams. Especially, it must not be used when pure is used in ZipAsyncM streams as pure in applicative zip streams generates an infinite stream causing unbounded concurrent generation with no limit on the buffer or threads.

valuesendToWorker :: MonadAsync m => Channel m a b -> a -> m (Maybe b)
#

Push values from a driver to a fold worker via a Channel. Blocks if no space is available in the buffer. Before pushing a value to the Channel it polls for events received from the fold worker. If a stop event is received then it returns True otherwise false. Propagates exceptions received from the fold worker.

datadata Channel (m :: Type -> Type) a b
#

The fold driver thread queues the input of the fold in the inputQueue The driver rings the doorbell when the queue transitions from empty to non-empty state.

The fold consumer thread dequeues the input items from the inputQueue and supplies them to the fold. When the fold is done the output of the fold is placed in inputQueue and outputDoorBell is rung.

The fold driver thread keeps watching the outputQueue, if the fold has terminated, it stops queueing the input to the inputQueue

If the fold driver runs out of input it stops and waits for the fold to drain the buffered input.

Driver thread ------>------Input Queue and Doorbell ----->-----Fold thread

Driver thread ------<------Output Queue and Doorbell-----<-----Fold thread

Constructors

datadata Config
#

An abstract type for specifying the configuration parameters of a Channel. Use Config -> Config modifier functions to modify the default configuration. See the individual modifier documentation for default values.

Concurrency

11 declarations
valueparBuffered
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> Fold m a b
  4. -> Fold m a b
#

parBuffered introduces a concurrent stage at the input of the fold. The inputs are asynchronously queued in a buffer and evaluated concurrently with the evaluation of the source stream. On finalization, parBuffered waits for the asynchronous fold to complete before it returns.

In the following example both the stream and the fold have a 1 second delay, but the delay is not compounded because both run concurrently.

Example1 expression
delay x = threadDelay 1000000 >> print x >> return x
Example3 expressions
src = Stream.delay 1 (Stream.enumerateFromTo 1 3)dst = Fold.parBuffered id (Fold.lmapM delay Fold.sum)Stream.fold dst src...

Another example:

Example1 expression
Stream.toList $ Stream.groupsOf 4 dst src...
valueparDemuxScan
  1. :: (MonadAsync m, Ord k)
  2. => Config -> Config
  3. -> a -> k
  4. -> k -> m (Fold m a b)
  5. -> Stream m a
  6. -> Stream m [(k, b)]
#

Evaluate a stream and send its outputs to the selected fold. The fold is dynamically selected using a key at the time of the first input seen for that key. Any new fold is added to the list of folds which are currently running. If there are no folds available for a given key, the input is discarded. If a fold completes its output is emitted in the output of the scan.

Example9 expressions
import qualified Data.Map.Strict as Mapimport Data.Maybe (fromJust)f1 = ("even", Fold.take 2 Fold.sum)f2 = ("odd", Fold.take 2 Fold.sum)kv = Map.fromList [f1, f2]getFold k = return (fromJust $ Map.lookup k kv)getKey x = if even x then "even" else "odd"input = Stream.enumerateFromTo 1 10Stream.toList $ Fold.parDemuxScan id getKey getFold input...
valueparDistribute
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> [Fold m a b]
  4. -> Fold m a [b]
#

Distribute the input to all the folds in the supplied list concurrently.

Definition:

Example1 expression
parDistribute cfg = Fold.distribute . fmap (Fold.parBuffered cfg)

Example:

Example4 expressions
delay x = threadDelay 1000000 >> print x >> return xc = Fold.lmapM delay Fold.sumdst = Fold.parDistribute id [c,c,c]Stream.fold dst src...
valueparDistributeScan
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> m [Fold m a b]
  4. -> Stream m a
  5. -> Stream m [b]
#

Evaluate a stream and send its outputs to zero or more dynamically generated folds. It checks for any new folds at each input generation step. Any new fold is added to the list of folds which are currently running. If there are no folds available, the input is discarded. If a fold completes its output is emitted in the output of the scan.

Example4 expressions
import Data.IORefref <- newIORef [Fold.take 2 Fold.sum, Fold.take 2 Fold.length :: Fold.Fold IO Int Int]gen = atomicModifyIORef ref (\xs -> ([], xs))Stream.toList $ Fold.parDistributeScan id gen (Stream.enumerateFromTo 1 10)...
valueparEval :: MonadAsync m => (Config -> Config) -> Fold m a b -> Fold m a b
#

Deprecated. Please use parBuffered instead.

parBuffered introduces a concurrent stage at the input of the fold. The inputs are asynchronously queued in a buffer and evaluated concurrently with the evaluation of the source stream. On finalization, parBuffered waits for the asynchronous fold to complete before it returns.

In the following example both the stream and the fold have a 1 second delay, but the delay is not compounded because both run concurrently.

Example1 expression
delay x = threadDelay 1000000 >> print x >> return x
Example3 expressions
src = Stream.delay 1 (Stream.enumerateFromTo 1 3)dst = Fold.parBuffered id (Fold.lmapM delay Fold.sum)Stream.fold dst src...

Another example:

Example1 expression
Stream.toList $ Stream.groupsOf 4 dst src...
valueparLmapM :: (Config -> Config) -> (a -> m b) -> Fold m b r -> Fold m a r
#

Evaluate the mapped actions concurrently with respect to each other. The results may be unordered or ordered depending on the configuration.

Unimplemented

valueparPartition
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> Fold m b x
  4. -> Fold m c y
  5. -> Fold m (Either b c) (x, y)
#

Select first fold for Left input and second for Right input. Both folds run concurrently.

Definition

Example1 expression
parPartition cfg c1 c2 = Fold.partition (Fold.parBuffered cfg c1) (Fold.parBuffered cfg c2)

Example:

Example5 expressions
delay x = threadDelay 1000000 >> print x >> return xc1 = Fold.lmapM delay Fold.sumc2 = Fold.lmapM delay Fold.sumdst = Fold.parPartition id c1 c2Stream.fold dst $ (fmap (\x -> if even x then Left x else Right x)) src...
valueparTee
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> Fold m x a
  4. -> Fold m x b
  5. -> Fold m x (a, b)
#

Execute both the folds in a tee concurrently.

Definition:

Example1 expression
parTee cfg c1 c2 = Fold.teeWith (,) (Fold.parBuffered cfg c1) (Fold.parBuffered cfg c2)

Example:

Example5 expressions
delay x = threadDelay 1000000 >> print x >> return xc1 = Fold.lmapM delay Fold.sumc2 = Fold.lmapM delay Fold.lengthdst = Fold.parTee id c1 c2Stream.fold dst src...
valueparTeeWith
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> a -> b -> c
  4. -> Fold m x a
  5. -> Fold m x b
  6. -> Fold m x c
#

Execute both the folds in a tee concurrently.

Definition:

Example1 expression
parTeeWith cfg f c1 c2 = Fold.teeWith f (Fold.parBuffered cfg c1) (Fold.parBuffered cfg c2)

Example:

Example5 expressions
delay x = threadDelay 1000000 >> print x >> return xc1 = Fold.lmapM delay Fold.sumc2 = Fold.lmapM delay Fold.lengthdst = Fold.parTeeWith id (,) c1 c2Stream.fold dst src...
valueparUnzip
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> Fold m b x
  4. -> Fold m c y
  5. -> Fold m (b, c) (x, y)
#

Split and distribute the output to two different folds and then zip the results. Both the consumer folds run concurrently.

Definition

Example1 expression
parUnzip cfg c1 c2 = Fold.unzip (Fold.parBuffered cfg c1) (Fold.parBuffered cfg c2)

Example:

Example5 expressions
delay x = threadDelay 1000000 >> print x >> return xc1 = Fold.lmapM delay Fold.sumc2 = Fold.lmapM delay Fold.sumdst = Fold.parUnzip id c1 c2Stream.fold dst $ (fmap (\x -> (x, x * x))) src...
valueparUnzipWithM
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> a -> m (b, c)
  4. -> Fold m b x
  5. -> Fold m c y
  6. -> Fold m a (x, y)
#

Split and distribute the output to two different folds and then zip the results. Both the consumer folds run concurrently.

Definition

Example1 expression
parUnzipWithM cfg f c1 c2 = Fold.unzipWithM f (Fold.parBuffered cfg c1) (Fold.parBuffered cfg c2)

Example:

Example5 expressions
delay x = threadDelay 1000000 >> print x >> return xc1 = Fold.lmapM delay Fold.sumc2 = Fold.lmapM delay Fold.sumdst = Fold.parUnzipWithM id (pure . id) c1 c2Stream.fold dst $ (fmap (\x -> (x, x* x))) src...

Time

2 declarations
valueintervalsOf
  1. :: MonadAsync m
  2. => Double
  3. -> Fold m a b
  4. -> Fold m b c
  5. -> Fold m a c
#

Group the input stream into windows of n second each using the first fold and then fold the resulting groups using the second fold.

Example2 expressions
intervals = Fold.intervalsOf 0.5 Fold.toList Fold.toListStream.fold intervals $ Stream.delay 0.2 $ Stream.fromList [1..10][[1,2,3,4],[5,6,7],[8,9,10]]
intervalsOf n split = many (takeInterval n split)

Pre-release

valuetakeInterval :: MonadAsync m => Double -> Fold m a b -> Fold m a b
#

takeInterval n fold uses fold to fold the input items arriving within a window of first n seconds.

Example2 expressions
input = Stream.delay 0.2 $ Stream.fromList [1..10]Stream.fold (Fold.takeInterval 1.0 Fold.toList) input[1,2,3,4,5,6]
Example2 expressions
f = Fold.takeInterval 0.5 Fold.toListStream.fold Fold.toList $ Stream.foldMany f input[[1,2,3,4],[5,6,7],[8,9,10]]

Stops when fold stops or when the timeout occurs. Note that the fold needs an input after the timeout to stop. For example, if no input is pushed to the fold until one hour after the timeout had occurred, then the fold will be done only after consuming that input.

Pre-release

Deprecated

2 declarations
valuewrite :: MonadIO m => SVar t m a -> Maybe WorkerInfo -> Fold m a ()
#

A fold to write a stream to an SVar. Unlike toSVar this does not allow for concurrent evaluation of the stream, as the fold receives the input one element at a time, it just forwards the elements to the SVar. However, we can safely execute the fold in an independent thread, the SVar can act as a buffer decoupling the sender from the receiver. Also, we can have multiple folds running concurrently pusing the streams to the SVar.