Strict left associative fold.
Modulestreamly-core-0.2.2Haskell2010
Streamly.Internal.Data.StreamK
- 4 types
- 142 values
- Packagestreamly-core-0.2.2
- Exports146
- LanguageHaskell2010
- LicenceBSD-3-Clause
- SourceType.hs
Setup
0 declarationsTo execute the code examples provided in this module in ghci, please run the following commands first.
:mimport Control.Concurrent (threadDelay)import Data.Function (fix, (&))import Data.Semigroup (cycle1)
effect n = print n >> return nimport Streamly.Data.StreamK (StreamK)import qualified Streamly.Data.Fold as Foldimport qualified Streamly.Data.Parser as Parserimport qualified Streamly.Data.Stream as Streamimport qualified Streamly.Data.StreamK as StreamKimport qualified Streamly.FileSystem.Dir as Dir
For APIs that have not been released yet.
import qualified Streamly.Internal.Data.StreamK as StreamKimport qualified Streamly.Internal.FileSystem.Dir as Dir
The stream type
86 declarationsDeprecated. 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.appendLazy right associative fold.
A stream that terminates without producing any output or side effect.
Stream.fold Fold.toList (StreamK.toStream StreamK.nil)[]
Instances10Functor, Foldable, Traversable, IsList, Read, Show, …
Monad m => Functor (StreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type(Foldable m, Monad m) => Foldable (StreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeTraversable (StreamK Identity)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeIsList (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeRead a => Read (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeShow a => Show (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typea ~ Char => IsString (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeSemigroup (StreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonoid (StreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typetype Item (StreamK Identity a) = aDefined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type
Generate an infinite stream by repeating a pure value.
Pre-release
Extract all but the last element of the stream, if any.
Note: This will end up buffering the entire stream.
Pre-release
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
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.nilStream.fold Fold.drain (StreamK.toStream s)helloworld
It can be used efficiently with foldr:
fromFoldableM = Prelude.foldr StreamK.consM StreamK.nilSame as the following but more efficient:
consM x xs = StreamK.fromEffect x `StreamK.append` xsRun an action before evaluating the stream.
Like foldl' but with a monadic step function.
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.nilStream.fold Fold.toList (StreamK.toStream s)[1,2,3]
It can be used efficiently with foldr:
fromFoldable = Prelude.foldr StreamK.cons StreamK.nilSame as the following but more efficient:
cons x xs = return x `StreamK.consM` xs:{unfoldr step s = case step s of Nothing -> StreamK.nil Just (a, b) -> a `StreamK.cons` unfoldr step b:}
Build a stream by unfolding a pure step function step starting from a
seed s. The step function returns the next element in the stream and the
next seed value. When it is done it returns Nothing and the stream ends.
For example,
:{let f b = if b > 2 then Nothing else Just (b, b + 1)in StreamK.toList $ StreamK.unfoldr f 0:}[0,1,2]
Build a stream by unfolding a monadic step function starting from a seed. The step function returns the next element in the stream and the next seed value. When it is done it returns Nothing and the stream ends. For example,
:{let f b = if b > 2 then return Nothing else return (Just (b, b + 1))in StreamK.toList $ StreamK.unfoldrM f 0:}[0,1,2]
Lazy right fold with a monadic step function.
Note: When joining many streams in a left associative manner earlier streams will get exponential priority than the ones joining later. Because of exponentially high weighting of left streams it can be used with concatMapWith even on a large number of streams.
Definition:
crossWith f m1 m2 = fmap f m1 `StreamK.crossApply` m2Note that the second stream is evaluated multiple times.
fromFoldable = Prelude.foldr StreamK.cons StreamK.nilConstruct a stream from a Foldable containing pure values:
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.
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.fromPurecombine = StreamK.mergeBy compareStream.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
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.
Unwrap the StreamK type from CrossStreamK newtype.
This is a type level operation with no runtime overhead.
Like foldx, but with a monadic step function.
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.
Like interleave but stops interleaving as soon as any of the two streams stops.
Like interleave but stops interleaving as soon as the first stream stops.
Given a StreamK m a and StreamK m b generate a stream with all possible
combinations of the tuple (a, b).
Definition:
cross = StreamK.crossWith (,)The second stream is evaluated multiple times. If that is not desired it can be cached in an Array and then generated from the array before calling this function. Caching may also improve performance if the stream is expensive to evaluate.
See cross for a much faster fused alternative.
Time: O(m x n)
Pre-release
Right fold to a streaming monad.
foldrS StreamK.cons StreamK.nil === idfoldrS 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 xsinput = StreamK.fromStream (Stream.fromList (2:4:5:undefined)) :: StreamK IO IntStream.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 xsinput = StreamK.fromStream (Stream.fromList [1..5]) :: StreamK IO IntStream.fold Fold.toList $ StreamK.toStream $ StreamK.foldrS step StreamK.nil input[3,5,7]
Pre-release
Lazy left fold to a stream.
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.appendcrossApply = Stream.crossWith id
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)]
Instances15MonadTrans, Monad, Functor, Applicative, Foldable, Traversable, …
MonadTrans CrossStreamKDefined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonad m => Monad (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonad m => Functor (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonad m => Applicative (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type(Foldable m, Monad m) => Foldable (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeTraversable (CrossStreamK Identity)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonadIO m => MonadIO (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonadThrow m => MonadThrow (CrossStreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeIsList (CrossStreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeRead a => Read (CrossStreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeShow a => Show (CrossStreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typea ~ Char => IsString (CrossStreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeSemigroup (CrossStreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonoid (CrossStreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typetype Item (CrossStreamK Identity a) = Item (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type
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.
Make an empty stream from a stop function.
Make a singleton stream from a callback function. The callback function calls the one-shot yield continuation to yield an element.
Add a yield function at the head of the stream.
Operator equivalent of cons.
> toList $ 1 .: 2 .: 3 .: nil
[1,2,3]
Like repeatM but takes a stream cons operation to combine the actions
in a stream specific manner. A serial cons would repeat the values serially
while an async cons would repeat concurrently.
Pre-release
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 xensures 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
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.fromEffectPre-release
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
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
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
Lazy left fold to an arbitrary transformer monad.
Right associative fold to an arbitrary transformer monad.
Instances10Functor, Foldable, Traversable, IsList, Read, Show, …
Monad m => Functor (StreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type(Foldable m, Monad m) => Foldable (StreamK m)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeTraversable (StreamK Identity)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeIsList (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeRead a => Read (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeShow a => Show (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typea ~ Char => IsString (StreamK Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeSemigroup (StreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.TypeMonoid (StreamK m a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Typetype Item (StreamK Identity a) = aDefined in streamly-core-0.2.2 · Streamly.Internal.Data.StreamK.Type
Specialized Generation
repeatM = StreamK.sequence . StreamK.repeatrepeatM = fix . StreamK.consMrepeatM = cycle1 . StreamK.fromEffect
Generate a stream by repeatedly executing a monadic action forever.
:{repeatAction = StreamK.repeatM (threadDelay 1000000 >> print 1) & StreamK.take 10 & StreamK.fold Fold.drain:}
iterate f x = x `StreamK.cons` iterate f xGenerate an infinite stream with x as the first element and each
successive element derived by applying the function f on the previous
element.
StreamK.toList $ StreamK.take 5 $ StreamK.iterate (+1) 1[1,2,3,4,5]
iterateM f m = m >>= \a -> return a `StreamK.consM` iterateM f (f a)Generate an infinite stream with the first element generated by the action
m and each successive element derived by applying the monadic function
f on the previous element.
:{StreamK.iterateM (\x -> print x >> return (x + 1)) (return 0) & StreamK.take 3 & StreamK.toList:}01[0,1,2]
Elimination
0 declarationsGeneral Folds
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 ffold f = StreamK.parseD (Parser.fromFold f)
Example:
StreamK.fold Fold.sum $ StreamK.fromStream $ Stream.enumerateFromTo 1 1005050
Like fold but also returns the remaining stream. The resulting stream
would be StreamK.nil if the stream finished before the fold.
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
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
Run a Parser over a stream and return rest of the Stream.
Similar to parseBreak but works on singular elements.
Run a ParserK over a StreamK. Please use parseChunks where possible, for better performance.
Similar to parseBreak but works on generic arrays
Specialized Folds
Extract the last element of the stream, if any.
Map and Fold
Apply a monadic action to each element of the stream and discard the output of the action.
Conversions
Transformation
0 declarationsBy folding (scans)
Filtering
Mapping
Inserting
Deleting
Reordering
Sort the input stream using a supplied comparison function.
Sorting can be achieved by simply:
sortBy cmp = StreamK.mergeMapWith (StreamK.mergeBy cmp) StreamK.fromPureHowever, 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
Zipping
Zipping of n streams can be performed by combining the streams pair
wise using mergeMapWith with O(n * log n) time complexity. If used
with concatMapWith it will have O(n^2) performance.
Merging
Merging of n streams can be performed by combining the streams pair
wise using mergeMapWith to give O(n * log n) time complexity. If used
with concatMapWith it will have O(n^2) performance.
Transformation comprehensions
Exceptions
1 declarationLike Streamly.Data.Stream.Streamly.Data.Stream.handle but with one
significant difference, this function observes exceptions from the consumer
of the stream as well.
You can also convert StreamK to Stream and use exception handling from Stream module:
handle f s = StreamK.fromStream $ Stream.handle (\e -> StreamK.toStream (f e)) (StreamK.toStream s)Resource Management
1 declarationLike Streamly.Data.Stream.Streamly.Data.Stream.bracketIO but with one
significant difference, this function observes exceptions from the consumer
of the stream as well. Therefore, it cleans up the resource promptly when
the consumer encounters an exception.
You can also convert StreamK to Stream and use resource handling from Stream module:
bracketIO bef aft bet = StreamK.fromStream $ Stream.bracketIO bef aft (StreamK.toStream . bet)