streamly-core-0.1.0: Streaming, parsers, arrays and more
Copyright(c) 2017 Composewell Technologies
LicenseBSD3
Maintainerstreamly@composewell.com
Stabilityexperimental
PortabilityGHC
Safe HaskellSafe-Inferred
LanguageHaskell2010

Streamly.Internal.Data.Stream.StreamK

Description

 
Synopsis

Setup

To execute the code examples provided in this module in ghci, please run the following commands first.

>>> :m
>>> import Data.Function (fix, (&))
>>> import Data.Semigroup (cycle1)
>>> effect n = print n >> return n
>>> import Streamly.Data.StreamK (StreamK)
>>> import qualified Streamly.Data.Fold as Fold
>>> import qualified Streamly.Data.Parser as Parser
>>> import qualified Streamly.Data.Stream as Stream
>>> import qualified Streamly.Data.StreamK as StreamK
>>> import qualified Streamly.FileSystem.Dir as Dir

For APIs that have not been released yet.

>>> import qualified Streamly.Internal.Data.Stream.StreamK as StreamK
>>> import qualified Streamly.Internal.FileSystem.Dir as Dir

The stream type

type Stream = StreamK Source #

Deprecated: Please use StreamK instead.

Continuation Passing Style (CPS) version of Streamly.Data.Stream.Stream. Unlike Streamly.Data.Stream.Stream, StreamK can be composed recursively without affecting performance.

Semigroup instance appends two streams:

>>> (<>) = Stream.append

newtype StreamK m a Source #

Constructors

MkStream (forall r. State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) 

Instances

Instances details
(Foldable m, Monad m) => Foldable (StreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

fold :: Monoid m0 => StreamK m m0 -> m0 #

foldMap :: Monoid m0 => (a -> m0) -> StreamK m a -> m0 #

foldMap' :: Monoid m0 => (a -> m0) -> StreamK m a -> m0 #

foldr :: (a -> b -> b) -> b -> StreamK m a -> b #

foldr' :: (a -> b -> b) -> b -> StreamK m a -> b #

foldl :: (b -> a -> b) -> b -> StreamK m a -> b #

foldl' :: (b -> a -> b) -> b -> StreamK m a -> b #

foldr1 :: (a -> a -> a) -> StreamK m a -> a #

foldl1 :: (a -> a -> a) -> StreamK m a -> a #

toList :: StreamK m a -> [a] #

null :: StreamK m a -> Bool #

length :: StreamK m a -> Int #

elem :: Eq a => a -> StreamK m a -> Bool #

maximum :: Ord a => StreamK m a -> a #

minimum :: Ord a => StreamK m a -> a #

sum :: Num a => StreamK m a -> a #

product :: Num a => StreamK m a -> a #

Traversable (StreamK Identity) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

traverse :: Applicative f => (a -> f b) -> StreamK Identity a -> f (StreamK Identity b) #

sequenceA :: Applicative f => StreamK Identity (f a) -> f (StreamK Identity a) #

mapM :: Monad m => (a -> m b) -> StreamK Identity a -> m (StreamK Identity b) #

sequence :: Monad m => StreamK Identity (m a) -> m (StreamK Identity a) #

Monad m => Functor (StreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

fmap :: (a -> b) -> StreamK m a -> StreamK m b #

(<$) :: a -> StreamK m b -> StreamK m a #

a ~ Char => IsString (StreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Monoid (StreamK m a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

mempty :: StreamK m a #

mappend :: StreamK m a -> StreamK m a -> StreamK m a #

mconcat :: [StreamK m a] -> StreamK m a #

Semigroup (StreamK m a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

(<>) :: StreamK m a -> StreamK m a -> StreamK m a #

sconcat :: NonEmpty (StreamK m a) -> StreamK m a #

stimes :: Integral b => b -> StreamK m a -> StreamK m a #

IsList (StreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Associated Types

type Item (StreamK Identity a) #

Read a => Read (StreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Show a => Show (StreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

type Item (StreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

type Item (StreamK Identity a) = a

fromStream :: Monad m => Stream m a -> StreamK m a Source #

data CrossStreamK m a Source #

A newtype wrapper for the StreamK type adding a cross product style monad instance.

A Monad bind behaves like a for loop:

>>> :{
Stream.fold Fold.toList $ StreamK.toStream $ StreamK.unCross $ do
    x <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [1,2]
    -- Perform the following actions for each x in the stream
    return x
:}
[1,2]

Nested monad binds behave like nested for loops:

>>> :{
Stream.fold Fold.toList $ StreamK.toStream $ StreamK.unCross $ do
    x <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [1,2]
    y <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [3,4]
    -- Perform the following actions for each x, for each y
    return (x, y)
:}
[(1,3),(1,4),(2,3),(2,4)]

Instances

Instances details
MonadTrans CrossStreamK Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

lift :: Monad m => m a -> CrossStreamK m a #

MonadIO m => MonadIO (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

liftIO :: IO a -> CrossStreamK m a #

(Foldable m, Monad m) => Foldable (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

fold :: Monoid m0 => CrossStreamK m m0 -> m0 #

foldMap :: Monoid m0 => (a -> m0) -> CrossStreamK m a -> m0 #

foldMap' :: Monoid m0 => (a -> m0) -> CrossStreamK m a -> m0 #

foldr :: (a -> b -> b) -> b -> CrossStreamK m a -> b #

foldr' :: (a -> b -> b) -> b -> CrossStreamK m a -> b #

foldl :: (b -> a -> b) -> b -> CrossStreamK m a -> b #

foldl' :: (b -> a -> b) -> b -> CrossStreamK m a -> b #

foldr1 :: (a -> a -> a) -> CrossStreamK m a -> a #

foldl1 :: (a -> a -> a) -> CrossStreamK m a -> a #

toList :: CrossStreamK m a -> [a] #

null :: CrossStreamK m a -> Bool #

length :: CrossStreamK m a -> Int #

elem :: Eq a => a -> CrossStreamK m a -> Bool #

maximum :: Ord a => CrossStreamK m a -> a #

minimum :: Ord a => CrossStreamK m a -> a #

sum :: Num a => CrossStreamK m a -> a #

product :: Num a => CrossStreamK m a -> a #

Traversable (CrossStreamK Identity) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Monad m => Applicative (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

pure :: a -> CrossStreamK m a #

(<*>) :: CrossStreamK m (a -> b) -> CrossStreamK m a -> CrossStreamK m b #

liftA2 :: (a -> b -> c) -> CrossStreamK m a -> CrossStreamK m b -> CrossStreamK m c #

(*>) :: CrossStreamK m a -> CrossStreamK m b -> CrossStreamK m b #

(<*) :: CrossStreamK m a -> CrossStreamK m b -> CrossStreamK m a #

Monad m => Functor (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

fmap :: (a -> b) -> CrossStreamK m a -> CrossStreamK m b #

(<$) :: a -> CrossStreamK m b -> CrossStreamK m a #

Monad m => Monad (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

(>>=) :: CrossStreamK m a -> (a -> CrossStreamK m b) -> CrossStreamK m b #

(>>) :: CrossStreamK m a -> CrossStreamK m b -> CrossStreamK m b #

return :: a -> CrossStreamK m a #

MonadThrow m => MonadThrow (CrossStreamK m) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

throwM :: Exception e => e -> CrossStreamK m a #

a ~ Char => IsString (CrossStreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Monoid (CrossStreamK m a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Semigroup (CrossStreamK m a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Methods

(<>) :: CrossStreamK m a -> CrossStreamK m a -> CrossStreamK m a #

sconcat :: NonEmpty (CrossStreamK m a) -> CrossStreamK m a #

stimes :: Integral b => b -> CrossStreamK m a -> CrossStreamK m a #

IsList (CrossStreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Associated Types

type Item (CrossStreamK Identity a) #

Read a => Read (CrossStreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

Show a => Show (CrossStreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

type Item (CrossStreamK Identity a) Source # 
Instance details

Defined in Streamly.Internal.Data.Stream.StreamK.Type

unCross :: CrossStreamK m a -> StreamK m a Source #

Unwrap the StreamK type from CrossStreamK newtype.

This is a type level operation with no runtime overhead.

mkCross :: StreamK m a -> CrossStreamK m a Source #

Wrap the StreamK type in a CrossStreamK newtype to enable cross product style applicative and monad instances.

This is a type level operation with no runtime overhead.

Construction Primitives

mkStream :: (forall r. State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> m r) -> StreamK m a Source #

nil :: StreamK m a Source #

A stream that terminates without producing any output or side effect.

>>> Stream.fold Fold.toList (StreamK.toStream StreamK.nil)
[]

nilM :: Applicative m => m b -> StreamK m a Source #

A stream that terminates without producing any output, but produces a side effect.

>>> Stream.fold Fold.toList (StreamK.toStream (StreamK.nilM (print "nil")))
"nil"
[]

Pre-release

cons :: a -> StreamK m a -> StreamK m a infixr 5 Source #

A right associative prepend operation to add a pure value at the head of an existing stream::

>>> s = 1 `StreamK.cons` 2 `StreamK.cons` 3 `StreamK.cons` StreamK.nil
>>> Stream.fold Fold.toList (StreamK.toStream s)
[1,2,3]

It can be used efficiently with foldr:

>>> fromFoldable = Prelude.foldr StreamK.cons StreamK.nil

Same as the following but more efficient:

>>> cons x xs = return x `StreamK.consM` xs

(.:) :: a -> StreamK m a -> StreamK m a infixr 5 Source #

Operator equivalent of cons.

> toList $ 1 .: 2 .: 3 .: nil
[1,2,3]

Elimination Primitives

foldStream :: State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> StreamK m a -> m r Source #

Fold a stream by providing a State, stop continuation, a singleton continuation and a yield continuation. The stream will not use the SVar passed via State.

foldStreamShared :: State StreamK m a -> (a -> StreamK m a -> m r) -> (a -> m r) -> m r -> StreamK m a -> m r Source #

Fold a stream by providing an SVar, a stop continuation, a singleton continuation and a yield continuation. The stream would share the current SVar passed via the State.

Transformation Primitives

unShare :: StreamK m a -> StreamK m a Source #

Detach a stream from an SVar

Deconstruction

uncons :: Applicative m => StreamK m a -> m (Maybe (a, StreamK m a)) Source #

Generation

Unfolds

unfoldr :: (b -> Maybe (a, b)) -> b -> StreamK m a Source #

unfoldrM :: Monad m => (b -> m (Maybe (a, b))) -> b -> StreamK m a Source #

Specialized Generation

repeat :: a -> StreamK m a Source #

Generate an infinite stream by repeating a pure value.

Pre-release

repeatM :: Monad m => m a -> StreamK m a Source #

replicate :: Int -> a -> StreamK m a Source #

replicateM :: Monad m => Int -> m a -> StreamK m a Source #

fromIndices :: (Int -> a) -> StreamK m a Source #

fromIndicesM :: Monad m => (Int -> m a) -> StreamK m a Source #

iterate :: (a -> a) -> a -> StreamK m a Source #

iterateM :: Monad m => (a -> m a) -> m a -> StreamK m a Source #

Conversions

fromPure :: a -> StreamK m a Source #

Create a singleton stream from a pure value.

>>> fromPure a = a `StreamK.cons` StreamK.nil
>>> fromPure = pure
>>> fromPure = StreamK.fromEffect . pure

fromEffect :: Monad m => m a -> StreamK m a Source #

Create a singleton stream from a monadic action.

>>> fromEffect m = m `StreamK.consM` StreamK.nil
>>> Stream.fold Fold.drain $ StreamK.toStream $ StreamK.fromEffect (putStrLn "hello")
hello

fromFoldable :: Foldable f => f a -> StreamK m a Source #

>>> fromFoldable = Prelude.foldr StreamK.cons StreamK.nil

Construct a stream from a Foldable containing pure values:

fromList :: [a] -> StreamK m a Source #

foldr/build

foldrS :: (a -> StreamK m b -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b Source #

Right fold to a streaming monad.

foldrS StreamK.cons StreamK.nil === id

foldrS can be used to perform stateless stream to stream transformations like map and filter in general. It can be coupled with a scan to perform stateful transformations. However, note that the custom map and filter routines can be much more efficient than this due to better stream fusion.

>>> input = StreamK.fromStream $ Stream.fromList [1..5]
>>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS StreamK.cons StreamK.nil input
[1,2,3,4,5]

Find if any element in the stream is True:

>>> step x xs = if odd x then StreamK.fromPure True else xs
>>> input = StreamK.fromStream (Stream.fromList (2:4:5:undefined)) :: StreamK IO Int
>>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS step (StreamK.fromPure False) input
[True]

Map (+2) on odd elements and filter out the even elements:

>>> step x xs = if odd x then (x + 2) `StreamK.cons` xs else xs
>>> input = StreamK.fromStream (Stream.fromList [1..5]) :: StreamK IO Int
>>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS step StreamK.nil input
[3,5,7]

Pre-release

foldrSM :: Monad m => (m a -> StreamK m b -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b Source #

buildS :: ((a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a Source #

augmentS :: ((a -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a) -> StreamK m a -> StreamK m a Source #

Elimination

General Folds

foldr :: Monad m => (a -> b -> b) -> b -> StreamK m a -> m b Source #

Lazy right associative fold.

foldr1 :: Monad m => (a -> a -> a) -> StreamK m a -> m (Maybe a) Source #

foldrM :: (a -> m b -> m b) -> m b -> StreamK m a -> m b Source #

Lazy right fold with a monadic step function.

foldl' :: Monad m => (b -> a -> b) -> b -> StreamK m a -> m b Source #

Strict left associative fold.

foldlM' :: Monad m => (b -> a -> m b) -> m b -> StreamK m a -> m b Source #

Like foldl' but with a monadic step function.

foldlS :: (StreamK m b -> a -> StreamK m b) -> StreamK m b -> StreamK m a -> StreamK m b Source #

Lazy left fold to a stream.

foldlx' :: forall m a b x. Monad m => (x -> a -> x) -> x -> (x -> b) -> StreamK m a -> m b Source #

Strict left fold with an extraction function. Like the standard strict left fold, but applies a user supplied extraction function (the third argument) to the folded value at the end. This is designed to work with the foldl library. The suffix x is a mnemonic for extraction.

Note that the accumulator is always evaluated including the initial value.

foldlMx' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> StreamK m a -> m b Source #

Like foldx, but with a monadic step function.

fold :: Monad m => Fold m a b -> StreamK m a -> m b Source #

Fold a stream using the supplied left Fold and reducing the resulting expression strictly at each step. The behavior is similar to foldl'. A Fold can terminate early without consuming the full stream. See the documentation of individual Folds for termination behavior.

Definitions:

>>> fold f = fmap fst . StreamK.foldBreak f
>>> fold f = StreamK.parseD (Parser.fromFold f)

Example:

>>> StreamK.fold Fold.sum $ StreamK.fromStream $ Stream.enumerateFromTo 1 100
5050

foldBreak :: Monad m => Fold m a b -> StreamK m a -> m (b, StreamK m a) Source #

Like fold but also returns the remaining stream. The resulting stream would be nil if the stream finished before the fold.

foldEither :: Monad m => Fold m a b -> StreamK m a -> m (Either (Fold m a b) (b, StreamK m a)) Source #

Fold resulting in either breaking the stream or continuation of the fold. Instead of supplying the input stream in one go we can run the fold multiple times, each time supplying the next segment of the input stream. If the fold has not yet finished it returns a fold that can be run again otherwise it returns the fold result and the residual stream.

Internal

foldConcat :: Monad m => Producer m a b -> Fold m b c -> StreamK m a -> m (c, StreamK m a) Source #

Generate streams from individual elements of a stream and fold the concatenation of those streams using the supplied fold. Return the result of the fold and residual stream.

For example, this can be used to efficiently fold an Array Word8 stream using Word8 folds.

Internal

parseDBreak :: Monad m => Parser a m b -> StreamK m a -> m (Either ParseError b, StreamK m a) Source #

Run a Parser over a stream and return rest of the Stream.

parseD :: Monad m => Parser a m b -> StreamK m a -> m (Either ParseError b) Source #

parseBreakChunks :: (Monad m, Unbox a) => ParserK a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a)) Source #

Run a ParserK over a chunked StreamK and return the rest of the Stream.

parseChunks :: (Monad m, Unbox a) => ParserK a m b -> StreamK m (Array a) -> m (Either ParseError b) Source #

Specialized Folds

drain :: Monad m => StreamK m a -> m () Source #

drain = foldl' (\_ _ -> ()) ()
drain = mapM_ (\_ -> return ())

null :: Monad m => StreamK m a -> m Bool Source #

head :: Monad m => StreamK m a -> m (Maybe a) Source #

tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a)) Source #

init :: Applicative m => StreamK m a -> m (Maybe (StreamK m a)) Source #

Extract all but the last element of the stream, if any.

Note: This will end up buffering the entire stream.

Pre-release

elem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool Source #

notElem :: (Monad m, Eq a) => a -> StreamK m a -> m Bool Source #

all :: Monad m => (a -> Bool) -> StreamK m a -> m Bool Source #

any :: Monad m => (a -> Bool) -> StreamK m a -> m Bool Source #

last :: Monad m => StreamK m a -> m (Maybe a) Source #

Extract the last element of the stream, if any.

minimum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a) Source #

minimumBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a) Source #

maximum :: (Monad m, Ord a) => StreamK m a -> m (Maybe a) Source #

maximumBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> m (Maybe a) Source #

findIndices :: (a -> Bool) -> StreamK m a -> StreamK m Int Source #

lookup :: (Monad m, Eq a) => a -> StreamK m (a, b) -> m (Maybe b) Source #

findM :: Monad m => (a -> m Bool) -> StreamK m a -> m (Maybe a) Source #

find :: Monad m => (a -> Bool) -> StreamK m a -> m (Maybe a) Source #

(!!) :: Monad m => StreamK m a -> Int -> m (Maybe a) Source #

Map and Fold

mapM_ :: Monad m => (a -> m b) -> StreamK m a -> m () Source #

Apply a monadic action to each element of the stream and discard the output of the action.

Conversions

toList :: Monad m => StreamK m a -> m [a] Source #

hoist :: (Monad m, Monad n) => (forall x. m x -> n x) -> StreamK m a -> StreamK n a Source #

Transformation

By folding (scans)

scanl' :: (b -> a -> b) -> b -> StreamK m a -> StreamK m b Source #

scanlx' :: (x -> a -> x) -> x -> (x -> b) -> StreamK m a -> StreamK m b Source #

Filtering

filter :: (a -> Bool) -> StreamK m a -> StreamK m a Source #

take :: Int -> StreamK m a -> StreamK m a Source #

takeWhile :: (a -> Bool) -> StreamK m a -> StreamK m a Source #

drop :: Int -> StreamK m a -> StreamK m a Source #

dropWhile :: (a -> Bool) -> StreamK m a -> StreamK m a Source #

Mapping

map :: (a -> b) -> StreamK m a -> StreamK m b Source #

mapM :: Monad m => (a -> m b) -> StreamK m a -> StreamK m b Source #

sequence :: Monad m => StreamK m (m a) -> StreamK m a Source #

Inserting

intersperseM :: Monad m => m a -> StreamK m a -> StreamK m a Source #

intersperse :: Monad m => a -> StreamK m a -> StreamK m a Source #

insertBy :: (a -> a -> Ordering) -> a -> StreamK m a -> StreamK m a Source #

Deleting

deleteBy :: (a -> a -> Bool) -> a -> StreamK m a -> StreamK m a Source #

Reordering

sortBy :: Monad m => (a -> a -> Ordering) -> StreamK m a -> StreamK m a Source #

Sort the input stream using a supplied comparison function.

Sorting can be achieved by simply:

>>> sortBy cmp = StreamK.mergeMapWith (StreamK.mergeBy cmp) StreamK.fromPure

However, this combinator uses a parser to first split the input stream into down and up sorted segments and then merges them to optimize sorting when pre-sorted sequences exist in the input stream.

O(n) space

Map and Filter

mapMaybe :: (a -> Maybe b) -> StreamK m a -> StreamK m b Source #

Zipping

zipWith :: Monad m => (a -> b -> c) -> StreamK m a -> StreamK m b -> StreamK m c Source #

Zip two streams serially using a pure zipping function.

zipWithM :: Monad m => (a -> b -> m c) -> StreamK m a -> StreamK m b -> StreamK m c Source #

Zip two streams serially using a monadic zipping function.

Merging

mergeBy :: (a -> a -> Ordering) -> StreamK m a -> StreamK m a -> StreamK m a Source #

mergeByM :: Monad m => (a -> a -> m Ordering) -> StreamK m a -> StreamK m a -> StreamK m a Source #

Nesting

crossApplyWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> StreamK m (a -> b) -> StreamK m a -> StreamK m b Source #

crossApply :: StreamK m (a -> b) -> StreamK m a -> StreamK m b Source #

Apply a stream of functions to a stream of values and flatten the results.

Note that the second stream is evaluated multiple times.

Definition:

>>> crossApply = StreamK.crossApplyWith StreamK.append
>>> crossApply = Stream.crossWith id

crossWith :: Monad m => (a -> b -> c) -> StreamK m a -> StreamK m b -> StreamK m c Source #

Definition:

>>> crossWith f m1 m2 = fmap f m1 `StreamK.crossApply` m2

Note that the second stream is evaluated multiple times.

concatMapWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m a -> StreamK m b Source #

Perform a concatMap using a specified concat strategy. The first argument specifies a merge or concat function that is used to merge the streams generated by the map function.

concatMap :: (a -> StreamK m b) -> StreamK m a -> StreamK m b Source #

concatEffect :: Monad m => m (StreamK m a) -> StreamK m a Source #

concat . fromEffect

bindWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> StreamK m a -> (a -> StreamK m b) -> StreamK m b Source #

concatIterateWith :: (StreamK m a -> StreamK m a -> StreamK m a) -> (a -> StreamK m a) -> StreamK m a -> StreamK m a Source #

Yield an input element in the output stream, map a stream generator on it and repeat the process on the resulting stream. Resulting streams are flattened using the concatMapWith combinator. This can be used for a depth first style (DFS) traversal of a tree like structure.

Example, list a directory tree using DFS:

>>> f = StreamK.fromStream . either Dir.readEitherPaths (const Stream.nil)
>>> input = StreamK.fromPure (Left ".")
>>> ls = StreamK.concatIterateWith StreamK.append f input

Note that iterateM is a special case of concatIterateWith:

>>> iterateM f = StreamK.concatIterateWith StreamK.append (StreamK.fromEffect . f) . StreamK.fromEffect

Pre-release

concatIterateLeftsWith :: b ~ Either a c => (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m b -> StreamK m b Source #

In an Either stream iterate on Lefts. This is a special case of concatIterateWith:

>>> concatIterateLeftsWith combine f = StreamK.concatIterateWith combine (either f (const StreamK.nil))

To traverse a directory tree:

>>> input = StreamK.fromPure (Left ".")
>>> ls = StreamK.concatIterateLeftsWith StreamK.append (StreamK.fromStream . Dir.readEither) input

Pre-release

concatIterateScanWith :: Monad m => (StreamK m a -> StreamK m a -> StreamK m a) -> (b -> a -> m (b, StreamK m a)) -> m b -> StreamK m a -> StreamK m a Source #

Like iterateMap but carries a state in the stream generation function. This can be used to traverse graph like structures, we can remember the visited nodes in the state to avoid cycles.

Note that a combination of iterateMap and usingState can also be used to traverse graphs. However, this function provides a more localized state instead of using a global state.

See also: mfix

Pre-release

mergeMapWith :: (StreamK m b -> StreamK m b -> StreamK m b) -> (a -> StreamK m b) -> StreamK m a -> StreamK m b Source #

Combine streams in pairs using a binary combinator, the resulting streams are then combined again in pairs recursively until we get to a single combined stream. The composition would thus form a binary tree.

For example, you can sort a stream using merge sort like this:

>>> s = StreamK.fromStream $ Stream.fromList [5,1,7,9,2]
>>> generate = StreamK.fromPure
>>> combine = StreamK.mergeBy compare
>>> Stream.fold Fold.toList $ StreamK.toStream $ StreamK.mergeMapWith combine generate s
[1,2,5,7,9]

Note that if the stream length is not a power of 2, the binary tree composed by mergeMapWith would not be balanced, which may or may not be important depending on what you are trying to achieve.

Caution: the stream of streams must be finite

Pre-release

mergeIterateWith :: (StreamK m a -> StreamK m a -> StreamK m a) -> (a -> StreamK m a) -> StreamK m a -> StreamK m a Source #

Like concatIterateWith but uses the pairwise flattening combinator mergeMapWith for flattening the resulting streams. This can be used for a balanced traversal of a tree like structure.

Example, list a directory tree using balanced traversal:

>>> f = StreamK.fromStream . either Dir.readEitherPaths (const Stream.nil)
>>> input = StreamK.fromPure (Left ".")
>>> ls = StreamK.mergeIterateWith StreamK.interleave f input

Pre-release

Transformation comprehensions

the :: (Eq a, Monad m) => StreamK m a -> m (Maybe a) Source #

Semigroup Style Composition

append :: StreamK m a -> StreamK m a -> StreamK m a infixr 6 Source #

Appends two streams sequentially, yielding all elements from the first stream, and then all elements from the second stream.

>>> s1 = StreamK.fromStream $ Stream.fromList [1,2]
>>> s2 = StreamK.fromStream $ Stream.fromList [3,4]
>>> Stream.fold Fold.toList $ StreamK.toStream $ s1 `StreamK.append` s2
[1,2,3,4]

This has O(n) append performance where n is the number of streams. It can be used to efficiently fold an infinite lazy container of streams using concatMapWith et. al.

interleave :: StreamK m a -> StreamK m a -> StreamK m a infixr 6 Source #

Interleaves two streams, yielding one element from each stream alternately. When one stream stops the rest of the other stream is used in the output stream.

When joining many streams in a left associative manner earlier streams will get exponential priority than the ones joining later. Because of exponential weighting it can be used with concatMapWith even on a large number of streams.

Utilities

consM :: Monad m => m a -> StreamK m a -> StreamK m a infixr 5 Source #

A right associative prepend operation to add an effectful value at the head of an existing stream::

>>> s = putStrLn "hello" `StreamK.consM` putStrLn "world" `StreamK.consM` StreamK.nil
>>> Stream.fold Fold.drain (StreamK.toStream s)
hello
world

It can be used efficiently with foldr:

>>> fromFoldableM = Prelude.foldr StreamK.consM StreamK.nil

Same as the following but more efficient:

>>> consM x xs = StreamK.fromEffect x `StreamK.append` xs

mfix :: Monad m => (m a -> StreamK m a) -> StreamK m a Source #

We can define cyclic structures using let:

>>> let (a, b) = ([1, b], head a) in (a, b)
([1,1],1)

The function fix defined as:

>>> fix f = let x = f x in x

ensures that the argument of a function and its output refer to the same lazy value x i.e. the same location in memory. Thus x can be defined in terms of itself, creating structures with cyclic references.

>>> f ~(a, b) = ([1, b], head a)
>>> fix f
([1,1],1)

mfix is essentially the same as fix but for monadic values.

Using mfix for streams we can construct a stream in which each element of the stream is defined in a cyclic fashion. The argument of the function being fixed represents the current element of the stream which is being returned by the stream monad. Thus, we can use the argument to construct itself.

In the following example, the argument action of the function f represents the tuple (x,y) returned by it in a given iteration. We define the first element of the tuple in terms of the second.

>>> import System.IO.Unsafe (unsafeInterleaveIO)
>>> :{
main = Stream.fold (Fold.drainMapM print) $ StreamK.toStream $ StreamK.mfix f
    where
    f action = StreamK.unCross $ do
        let incr n act = fmap ((+n) . snd) $ unsafeInterleaveIO act
        x <- StreamK.mkCross $ StreamK.fromStream $ Stream.sequence $ Stream.fromList [incr 1 action, incr 2 action]
        y <- StreamK.mkCross $ StreamK.fromStream $ Stream.fromList [4,5]
        return (x, y)
:}

Note: you cannot achieve this by just changing the order of the monad statements because that would change the order in which the stream elements are generated.

Note that the function f must be lazy in its argument, that's why we use unsafeInterleaveIO on action because IO monad is strict.

Pre-release