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

GHC 9.14.1 · lts/ghc-9.14.x · 45dd537 · 2026-10-11

Modulestreamly-0.11.1Haskell2010

Streamly.Internal.Data.Scanl.Prelude

  • 3 types
  • 19 values
  • Packagestreamly-0.11.1
  • Exports22
  • 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

5 declarations
valueparDemuxScanM
  1. :: (MonadAsync m, Ord k)
  2. => Config -> Config
  3. -> a -> k
  4. -> k -> m (Scanl m a b)
  5. -> Stream m a
  6. -> Stream m [(k, b)]
#

Evaluate a stream by routing each input to a scan determined by a key.

For each distinct key, the first input encountered triggers the creation of a new scan (via the supplied key-to-scan function). This scan is then added to the set of currently active scans. Subsequent inputs with the same key are directed to the same scan.

If no scan can be created for a key, the input element is discarded.

When a constituent scan completes, its final output is emitted as part of the composed output stream. The output of parDemuxScanM is a stream of key–value pairs, where each value is the output produced by the scan corresponding to that key.

For a simpler interface, use parDemuxScan if you do not need the full flexibility of parDemuxScanM.

Example:

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

A pure variant of parDistributeScanM that uses a fixed list of scans.

The provided scans are started once and run concurrently for the duration of the stream. Each input element is distributed to all active scans, and their outputs are collected and emitted together.

Example:

Example2 expressions
xs = [Scanl.take 5 Scanl.sum, Scanl.take 5 Scanl.length :: Scanl.Scanl IO Int Int]Stream.toList $ Scanl.parDistributeScan id xs (Stream.enumerateFromTo 1 10)...
valueparDistributeScanM
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> m [Scanl m a b]
  4. -> Stream m a
  5. -> Stream m [b]
#

Evaluate a stream by distributing its inputs across zero or more concurrently running scans. New scans can be generated dynamically. Use parDistributeScan for an eaiser to use interface, if you do not need the power of parDistributeScanM.

Before processing each input element, the supplied action is executed to produce additional scans. These scans are appended to the set of currently active scans. If you do not want the same scan to be added repeatedly, ensure that the action only generates it once (see the example below).

If there are no scans currently active, the input element is discarded. The results from all active scans are collected and lattened into the the output stream.

Concurrency and buffering:

If the input buffer (see maxBuffer) is bounded, a scan may block until space becomes available. If any scan is blocked on buffer, all scans are blocked. Processing continues only when all scans have buffer space available.

Example:

Example4 expressions
import Data.IORefref <- newIORef [Scanl.take 5 Scanl.sum, Scanl.take 5 Scanl.length :: Scanl.Scanl IO Int Int]gen = atomicModifyIORef ref (\xs -> ([], xs))Stream.toList $ Scanl.parDistributeScanM id gen (Stream.enumerateFromTo 1 10)...
valueparTeeWith
  1. :: MonadAsync m
  2. => Config -> Config
  3. -> a -> b -> c
  4. -> Scanl m x a
  5. -> Scanl m x b
  6. -> Scanl m x c
#

Execute both the scans in a tee concurrently.

Example:

Example6 expressions
src = Stream.delay 1 (Stream.enumerateFromTo 1 3)delay x = threadDelay 1000000 >> print x >> return xc1 = Scanl.lmapM delay Scanl.sumc2 = Scanl.lmapM delay Scanl.lengthdst = Scanl.parTeeWith id (,) c1 c2Stream.toList $ Stream.scanl dst src...