Modulestreamly-core-0.3.1Haskell2010
Streamly.Internal.Data.Fold
See Streamly.Data.Fold for an overview and
Streamly.Internal.Data.Fold.Type for design notes.
- 4 types
- 233 values
- Packagestreamly-core-0.3.1
- Exports237
- LanguageHaskell2010
- LicenceBSD-3-Clause
- SourceFold.hs
Imports
237 declarations:m:set -XFlexibleContextsimport Control.Monad (void)import qualified Data.Foldable as Foldableimport Data.Bifunctor(bimap)import Data.Function ((&))import Data.Functor.Identity (Identity, runIdentity)import Data.IORef (newIORef, readIORef, writeIORef)import Data.Maybe (fromJust, isJust)import Data.Monoid (Endo(..), Last(..), Sum(..))
import Streamly.Data.Array (Array)import Streamly.Data.Fold (Fold, Tee(..))import Streamly.Data.Stream (Stream)
import qualified Data.Map as Mapimport qualified Data.Set as Setimport qualified Data.IntSet as IntSetimport qualified Streamly.Data.Array as Arrayimport qualified Streamly.Data.Fold as Foldimport qualified Streamly.Data.MutArray as MutArrayimport qualified Streamly.Data.Parser as Parserimport qualified Streamly.Data.Stream as Streamimport qualified Streamly.Data.StreamK as StreamKimport qualified Streamly.Data.Unfold as Unfold
For APIs that have not been released yet.
import qualified Streamly.Internal.Data.Fold as Foldimport qualified Streamly.Internal.Data.Scanl as Scanlimport qualified Streamly.Internal.Data.Stream as Stream
Map a monadic function over the result b in Step s b.
Internal
Append a singleton value to the fold.
See examples under addStream.
Pre-release
Remove the either wrapper and flatten both lefts and as well as rights in the output stream.
Definition:
catEithers = Fold.lmap (either id id)Pre-release
Close a fold so that it does not accept any more input.
Map a Fold returning function on the result of a Fold and run the returned fold. This is akin to an n-ary version of splitWith where the next fold for splitting the input is decided dynamically using the previous result. This operation can be used to express data dependencies between fold operations.
Let's say the first element in the stream is a count of the following elements that we have to add, then:
import Data.Maybe (fromJust)count = fmap fromJust Fold.onetotal n = Fold.take n Fold.sumStream.fold (Fold.concatMap total count) $ Stream.fromList [10,9..1]45
This does not fuse completely, see refold for a fusible alternative.
Time: O(n^2) where n is the number of compositions.
See also: foldIterateM, refold
A fold that drains all its input, running the effects and discarding the results.
drain = Fold.drainMapM (const (return ()))drain = Fold.foldl' (\_ _ -> ()) ()
duplicate provides the ability to run a fold in parts. The duplicated fold consumes the input and returns the same fold as output instead of returning the final result, the returned fold can be run later to consume more input.
duplicate essentially appends a stream to the fold without finishing the fold. Compare with snoc which appends a singleton value to the fold.
Pre-release
Deprecated. Please use finalM instead
Extract the accumulated result of the fold.
Definition:
extractM = Fold.drive Stream.nilPre-release
Include only those elements that pass a predicate.
Stream.fold (Fold.filter (> 5) Fold.sum) $ Stream.fromList [1..10]40
filter p = Fold.filterM (return . p)filter p = Fold.mapMaybe (\x -> if p x then Just x else Nothing)
Like filter but with a monadic predicate.
f p x = p x >>= \r -> return $ if r then Just x else NothingfilterM p = Fold.mapMaybeM (f p)
A scanning fold for filtering elements based on a predicate.
Finalize a fold and extract the accumulated result of the fold.
Definition:
finalM = Fold.drive Stream.nilExample:
Fold.finalM Fold.toList[]
Pre-release
Make a fold from a left fold style pure step function and initial value of the accumulator.
If your Fold returns only Partial (i.e. never returns a Done) then you
can use foldl'* constructors.
A fold with an extract function can be expressed using fmap:
mkfoldlx :: Monad m => (s -> a -> s) -> s -> (s -> b) -> Fold m a b
mkfoldlx step initial extract = fmap extract (foldl' step initial)
Make a strict left fold, for non-empty streams, using first element as the starting value. Returns Nothing if the stream is empty.
Pre-release
Like 'foldl1'' but with a monadic step function.
Pre-release
Make a fold from a left fold style monadic step function and initial value of the accumulator.
A fold with an extract function can be expressed using rmapM:
mkFoldlxM :: Functor m => (s -> a -> m s) -> m s -> (s -> m b) -> Fold m a b
mkFoldlxM step initial extract = rmapM extract (foldlM' step initial)
Deprecated. Please use foldl1M' instead
Like 'foldl1'' but with a monadic step function.
Pre-release
Deprecated. Please use foldr' instead.
Make a fold using a right fold style step function and a terminal value. It performs a strict right fold via a left fold using function composition. Note that a strict right fold can only be useful for constructing strict structures in memory. For reductions this will be very inefficient.
Definitions:
foldr' f z = fmap (flip appEndo z) $ Fold.foldMap (Endo . f)foldr' f z = fmap ($ z) $ Fold.foldl' (\g x -> g . f x) id
Example:
Stream.fold (Fold.foldr' (:) []) $ Stream.enumerateFromTo 1 5[1,2,3,4,5]
Like foldr' but with a monadic step function.
Example:
toList = Fold.foldrM' (\a xs -> return $ a : xs) (return [])See also: foldrM
Pre-release
Make a terminating fold using a pure step function, a pure initial state and a pure state extraction function.
Pre-release
Make a terminating fold with an effectful step function and initial state, and a state extraction function.
foldtM' = Fold.FoldWe can just use Fold but it is provided for completeness.
Pre-release
Make a fold that yields the result of the supplied effectful action without consuming any further input.
Pre-release
Make a fold that yields the supplied value without consuming any further input.
Pre-release
Make a fold from a consumer.
Internal
Convert a left scan to a fold.
Adapt a pure fold to any monad.
generalizeInner = Fold.morphInner (return . runIdentity)Pre-release
groupsOf n split collect repeatedly applies the split fold to chunks
of n items in the input stream and supplies the result to the collect
fold.
Definition:
groupsOf n split = Fold.many (Fold.take n split)Example:
twos = Fold.groupsOf 2 Fold.toList Fold.toListStream.fold twos $ Stream.fromList [1..10][[1,2],[3,4],[5,6],[7,8],[9,10]]
Stops when collect stops.
Evaluate a condition, if True then use the first fold otherwise use the second fold.
Check if the fold has terminated and can take no more input.
Pre-release
Deprecated. Please use latest instead.
Returns the latest element of the input stream, if any.
latest = Fold.foldl1' (\_ x -> x)latest = fmap getLast $ Fold.foldMap (Last . Just)
Determine the length of the input stream.
Definition:
length = Fold.genericLengthlength = fmap getSum $ Fold.foldMap (Sum . const 1)
lmap f fold maps the function f on the input of the fold.
Definition:
lmap = Fold.lmapM returnExample:
sumSquared = Fold.lmap (\x -> x * x) Fold.sumStream.fold sumSquared (Stream.enumerateFromTo 1 100)338350
lmapM f fold maps the monadic function f on the input of the fold.
Longest alternative. Apply both folds in parallel but choose the result from the one which consumed more input i.e. take the longest succeeding fold.
If both the folds finish at the same time or if the result is extracted before any of the folds could finish then the left one is taken.
Pre-release
Collect zero or more applications of a fold. many first second applies
the first fold repeatedly on the input stream and accumulates it's results
using the second fold.
two = Fold.take 2 Fold.toListtwos = Fold.many two Fold.toListStream.fold twos $ Stream.fromList [1..10][[1,2],[3,4],[5,6],[7,8],[9,10]]
Stops when second fold stops.
See also: Data.Stream.concatMap, Data.Stream.foldMany
Like many, but the "first" fold emits an output at the end even if no input is received.
Internal
See also: Data.Stream.concatMap, Data.Stream.foldMany
Change the underlying monad of a fold. Also known as hoist.
Pre-release
postscanl scanner collector postscans the input of the collector fold
to change it in a stateful manner using scanner.
Pre-release
Use a Maybe returning left scan for filtering the input of a fold.
scanlMaybe p f = Fold.postscanl p (Fold.catMaybes f)Pre-release
Evaluate the initialization effect of a fold. If we are building the fold by chaining lazy actions in fold init this would reduce the actions to a strict accumulator value.
Pre-release
Map a monadic function on the output of a fold.
Deprecated. Please use postscanlMaybe instead.
Use a Maybe returning fold as a filtering scan.
> scanMaybe p f = Fold.postscan p (Fold.catMaybes f)Pre-release
Deprecated. Please use "splitWith" instead
Shortest alternative. Apply both folds in parallel but choose the result from the one which consumed least input i.e. take the shortest succeeding fold.
If both the folds finish at the same time or if the result is extracted before any of the folds could finish then the left one is taken.
Pre-release
Append a singleton value to the fold, in other words run a single step of the fold.
Example:
import qualified Data.Foldable as FoldableFoldable.foldlM Fold.snoc Fold.toList [1..3] >>= Fold.drive Stream.nil[1,2,3]
Pre-release
Append a singleton value to the fold in other words run a single step of the fold.
Definition:
snocM f = Fold.reduce . Fold.snoclM fPre-release
Append a singleton value to the fold lazily, in other words run a single step of the fold.
Definition:
snocl f = Fold.snoclM f . returnExample:
import qualified Data.Foldable as FoldableFold.finalM $ Foldable.foldl Fold.snocl Fold.toList [1..3][1,2,3]
Pre-release
Append an effect to the fold lazily, in other words run a single step of the fold.
Pre-release
Sequential fold application. Apply two folds sequentially to an input stream. The input is provided to the first fold, when it is done - the remaining input is provided to the second fold. When the second fold is done or if the input stream is over, the outputs of the two folds are combined using the supplied function.
Example:
header = Fold.take 8 Fold.toListline = Fold.takeEndBy (== '\n') Fold.toListf = Fold.splitWith (,) header lineStream.fold f $ Stream.fromList "header: hello\n"("header: ","hello\n")
Note: This is dual to appending streams using Data.Stream.append.
Note: this implementation allows for stream fusion but has quadratic time complexity, because each composition adds a new branch that each subsequent fold's input element has to traverse, therefore, it cannot scale to a large number of compositions. After around 100 compositions the performance starts dipping rapidly compared to a CPS style implementation.
For larger number of compositions you can convert the fold to a parser and use ParserK.
Time: O(n^2) where n is the number of compositions.
Same as applicative *>. Run two folds serially one after the other discarding the result of the first.
This was written in the hope that it might be faster than implementing it using splitWith, but the current benchmarks show that it has the same performance. So do not expose it unless some benchmark shows benefit.
Take at most n input elements and fold them using the supplied fold. A
negative count is treated as 0.
Stream.fold (Fold.take 2 Fold.toList) $ Stream.fromList [1..10][1,2]
Take the input, stop when the predicate succeeds taking the succeeding element as well.
Example:
input = Stream.fromList "hello\nthere\n"line = Fold.takeEndBy (== '\n') Fold.toListStream.fold line input"hello\n"
Stream.fold Fold.toList $ Stream.foldMany line input["hello\n","there\n"]
Like takeEndBy but drops the element on which the predicate succeeds.
Example:
input = Stream.fromList "hello\nthere\n"line = Fold.takeEndBy_ (== '\n') Fold.toListStream.fold line input"hello"
Stream.fold Fold.toList $ Stream.foldMany line input["hello","there"]
teeWith k f1 f2 distributes its input to both f1 and f2 until both
of them terminate and combines their output using k.
Definition:
teeWith k f1 f2 = fmap (uncurry k) (Fold.tee f1 f2)Example:
avg = Fold.teeWith (/) Fold.sum (fmap fromIntegral Fold.length)Stream.fold avg $ Stream.fromList [1.0..100.0]50.5
For applicative composition using this combinator see
Streamly.Data.Fold.Tee.
See also: Streamly.Data.Fold.Tee
Note that nested applications of teeWith do not fuse.
Like teeWith but terminates as soon as the first fold terminates.
Pre-release
Like teeWith but terminates as soon as any one of the two folds terminates.
Pre-release
Folds the input stream to a list.
Warning! working on large lists accumulated as buffers in memory could be very inefficient, consider using Streamly.Data.Array instead.
toList = Fold.foldr' (:) []Buffers the input stream to a list in the reverse order of the input.
Definition:
toListRev = Fold.foldl' (flip (:)) []Warning! working on large lists accumulated as buffers in memory could be
very inefficient, consider using Streamly.Array instead.
A fold that buffers its input to a pure stream.
toStreamK = foldr StreamK.cons StreamK.niltoStreamK = fmap StreamK.reverse Fold.toStreamKRev
Internal
Buffers the input stream to a pure stream in the reverse order of the input.
toStreamKRev = Foldable.foldl' (flip StreamK.cons) StreamK.nilThis is more efficient than toStreamK. toStreamK has exactly the same performance as reversing the stream after toStreamKRev.
Pre-release
The type Fold m a b represents a consumer of an input stream of values
of type a and returning a final value of type b in Monad m. The
constructor of a fold is Fold step initial extract final.
The fold uses an internal state of type s. The initial value of the state
s is created by initial. This function is called once and only once
before the fold starts consuming input. Any resource allocation can be done
in this function.
The step function is called on each input, it consumes an input and
returns the next intermediate state (see Step) or the final result b if
the fold terminates.
Folds are no longer used for scanning, please see the Streamly.Data.Scanl
module for scanning. The extract operation is no longer used and will be
removed in future.
Before a fold terminates, final is called once and only once (unless the
fold terminated in initial itself). Any resources allocated by initial
can be released in final.
When implementing fold combinators, care should be taken to cleanup any
state of the argument folds held by the fold by calling the respective
final at all exit points of the fold. Also, final should not be called
more than once. Note that if a fold terminates by Done constructor, there
is no state to cleanup.
NOTE: The constructor is not yet released, smart constructors are provided to create folds.
Instances2Functor, Applicative
Functor m => Functor (Fold m a)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.TypeMaps a function on the output of the fold (the type
b).Monad m => Applicative (Fold m a)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.TypeApplicative form of splitWith. Split the input serially over two folds. Note that this fuses but performance degrades quadratically with respect to the number of compositions. It should be good to use for less than 8 compositions.
Deprecated. Please use unTee instead.
Tee is a newtype wrapper over the Fold type providing distributing
Applicative, Semigroup, Monoid, Num, Floating and Fractional
instances.
The input received by the composed Tee is replicated and distributed to the constituent folds of the Tee.
For example, to compute the average of numbers in a stream without going through the stream twice:
avg = (/) <$> (Tee Fold.sum) <*> (Tee $ fmap fromIntegral Fold.length)Stream.fold (unTee avg) $ Stream.fromList [1.0..100.0]50.5
Similarly, the Semigroup and Monoid instances of Tee distribute the input to both the folds and combine the outputs using Monoid or Semigroup instances of the output types:
import Data.Monoid (Sum(..))t = Tee Fold.one <> Tee Fold.latestStream.fold (unTee t) (fmap Sum $ Stream.enumerateFromTo 1.0 100.0)Just (Sum {getSum = 101.0})
The Num, Floating, and Fractional instances work in the same way.
Instances7Functor, Applicative, Floating, Fractional, Num, Semigroup, …
Functor m => Functor (Tee m a)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.TeeMonad m => Applicative (Tee m a)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.Tee(Monad m, Floating b) => Floating (Tee m a b)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.Tee(Monad m, Fractional b) => Fractional (Tee m a b)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.TeeBinary Fractional operations distribute the input to both the argument Tees and combine their outputs using the Fractional instance of the output type.
(Monad m, Num b) => Num (Tee m a b)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.Tee(Semigroup b, Monad m) => Semigroup (Tee m a b)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.Tee(Monoid b, Monad m) => Monoid (Tee m a b)Defined in streamly-core-0.3.1 · Streamly.Internal.Data.Fold.Tee
Append a stream to a fold to build the fold accumulator incrementally. We
can repeatedly call addStream on the same fold to continue building the
fold and finally use drive to finish the fold and extract the result. Also
see the Streamly.Data.Fold.addOne operation which is a singleton version
of addStream.
Definitions:
addStream stream = Fold.drive stream . Fold.duplicateExample, build a list incrementally:
:{pure (Fold.toList :: Fold IO Int [Int]) >>= Fold.addOne 1 >>= Fold.addStream (Stream.enumerateFromTo 2 4) >>= Fold.drive Stream.nil >>= print:}[1,2,3,4]
This can be used as an O(n) list append compared to the O(n^2) ++ when
used for incrementally building a list.
Example, build a stream incrementally:
:{pure (Fold.toStream :: Fold IO Int (Stream Identity Int)) >>= Fold.addOne 1 >>= Fold.addStream (Stream.enumerateFromTo 2 4) >>= Fold.drive Stream.nil >>= print:}fromList [1,2,3,4]
This can be used as an O(n) stream append compared to the O(n^2) <> when
used for incrementally building a stream.
Example, build an array incrementally:
:{pure (Array.create :: Fold IO Int (Array Int)) >>= Fold.addOne 1 >>= Fold.addStream (Stream.enumerateFromTo 2 4) >>= Fold.drive Stream.nil >>= print:}fromList [1,2,3,4]
Example, build an array stream incrementally:
:{let f :: Fold IO Int (Stream Identity (Array Int)) f = Fold.groupsOf 2 (Array.createOf 3) Fold.toStreamin pure f >>= Fold.addOne 1 >>= Fold.addStream (Stream.enumerateFromTo 2 4) >>= Fold.drive Stream.nil >>= print:}fromList [fromList [1,2],fromList [3,4]]
Returns True if all elements of the input satisfy the predicate.
Definition:
all p = Fold.lmap p Fold.andExample:
Stream.fold (Fold.all (== 0)) $ Stream.fromList [1,0,1]False
Returns True if any element of the input satisfies the predicate.
Definition:
any p = Fold.lmap p Fold.orExample:
Stream.fold (Fold.any (== 0)) $ Stream.fromList [1,0,1]True
Fold the input stream to bottom n elements.
Definition:
bottom = Fold.bottomBy comparestream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]Stream.fold (Fold.bottom 3) stream >>= MutArray.toList[1,2,3]
Pre-release
Get the bottom most n elements using the supplied comparison function.
Group the input stream into groups of elements between low and high.
Collection starts in chunks of low and then keeps doubling until we reach
high. Each chunk is folded using the provided fold function.
This could be useful, for example, when we are folding a stream of unknown size to a stream of arrays and we want to minimize the number of allocations.
NOTE: this would be an application of "many" using a terminating fold.
Unimplemented
concatSequence f t applies folds from stream t sequentially and
collects the results using the fold f.
Unimplemented
Returns the latest element omitting the first occurrence that satisfies the given equality predicate.
Example:
input = Stream.fromList [1,3,3,5]> Stream.toList $ Stream.scanMaybe (Fold.deleteBy (==) 3) input- 1,3,5
Distribute one copy of the stream to each fold and collect the results in a container.
|-------Fold m a b--------|
---stream m a---| |---m [b]
|-------Fold m a b--------|
| |
...
Stream.fold (Fold.distribute [Fold.sum, Fold.length]) (Stream.enumerateFromTo 1 5)[15,5]
distribute = Prelude.foldr (Fold.teeWith (:)) (Fold.fromPure [])This is the consumer side dual of the producer side sequence operation.
Stops when all the folds stop.
Distribute the input to the folds returned by an effect. The effect is executed every time an input is processed, and the folds returned by it are added to the distribution list. The scan returns the results of the folds as they complete. To avoid adding the same folds repeatedly, the action must return the folds only once e.g. it can be implemented using modifyIORef replacing the original value by an empty list before returning it.
import Data.IORefref <- newIORef [Fold.take 2 Fold.sum, Fold.take 2 Fold.length :: Fold IO Int Int]gen = atomicModifyIORef ref (\xs -> ([], xs))Stream.toList $ Stream.scanl (Fold.distributeScan gen) (Stream.enumerateFromTo 1 10)[[],[],[],[2,3],[],[],[],[],[],[],[]]
Deprecated. Please use drainMapM instead.
Definitions:
drainMapM f = Fold.lmapM f Fold.draindrainMapM f = Fold.foldMapM (void . f)
Drain all input after passing it through a monadic function. This is the dual of mapM_ on stream producers.
A fold that drains the first n elements of its input, running the effects and discarding the results.
Definition:
drainN n = Fold.take n Fold.drainPre-release
Drive a fold using the supplied Stream, reducing the resulting expression strictly at each step.
Definition:
drive = flip Stream.foldExample:
Fold.drive (Stream.enumerateFromTo 1 100) Fold.sum5050
droppingWhile p = Fold.droppingWhileM (return . p)Return True if the given element is present in the stream.
Definition:
elem a = Fold.any (== a)Returns the first index where a given value is found in the stream.
Definition:
elemIndex a = Fold.findIndex (== a)Returns the index of the latest element if the element matches the given value.
Definition:
elemIndices a = Fold.findIndices (== a)Returns the first element that satisfies the given predicate.
Returns the first index that satisfies the given predicate.
Returns the index of the latest element if the element satisfies the given predicate.
Returns the first element that satisfies the given predicate.
Pre-release
Deprecated. Please use "one" instead
Extract the first element of the stream, if any.
head = Fold.oneReturn the element at the given index.
Definition:
index = Fold.genericIndexPair each element of a fold input with its index, starting from index 0.
indexed = Fold.postscanlMaybe Scanl.indexingDeprecated. Use Scanl.indexing instead
> indexing = Fold.indexingWith 0 (+ 1)Deprecated. Use Scanl.indexingRev instead
> indexingRev n = Fold.indexingWith n (subtract 1)Deprecated. Use Scanl.indexingWith instead
Pair each element of a fold input with its index, starting from index 0.
In a stream of (key-value) pairs (a, b), return the value b of the
first pair where the key equals the given value a.
Definition:
lookup x = fmap snd <$> Fold.find ((== x) . fst)Deprecated. Use rmapM instead
Map a monadic function on the output of a fold.
mapMaybe f fold maps a Maybe returning function f on the input of
the fold, filters out Nothing elements, and return the values extracted
from Just.
mapMaybe f = Fold.lmap f . Fold.catMaybesmapMaybe f = Fold.mapMaybeM (return . f)
f x = if even x then Just x else Nothingfld = Fold.mapMaybe f Fold.toListStream.fold fld (Stream.enumerateFromTo 1 10)[2,4,6,8,10]
mapMaybeM f = Fold.lmapM f . Fold.catMaybesDetermine the maximum element in a stream.
Definitions:
maximum = Fold.maximumBy comparemaximum = Fold.foldl1' max
Same as the following but without a default maximum. The Max Monoid uses
the minBound as the default maximum:
maximum = fmap Data.Semigroup.getMax $ Fold.foldMap Data.Semigroup.MaxDetermine the maximum element in a stream using the supplied comparison function.
Consume a single input and transform it using the supplied Maybe returning function.
Pre-release
Compute a numerically stable arithmetic mean of all elements in the input stream.
Determine the minimum element in a stream using the supplied comparison function.
Definitions:
minimum = Fold.minimumBy compareminimum = Fold.foldl1' min
Same as the following but without a default minimum. The Min Monoid uses the
maxBound as the default maximum:
maximum = fmap Data.Semigroup.getMin $ Fold.foldMap Data.Semigroup.MinComputes the minimum element with respect to the given comparison function
Returns True if the given element is not present in the stream.
Definition:
notElem a = Fold.all (/= a)Take one element from the stream and stop.
Definition:
one = Fold.maybe JustThis is similar to the stream Stream.uncons operation.
Same as partitionByM but with a pure partition function.
Example, count even and odd numbers in a stream:
:{ let f = Fold.partitionBy (\n -> if even n then Left n else Right n) (fmap (("Even " ++) . show) Fold.length) (fmap (("Odd " ++) . show) Fold.length) in Stream.fold f (Stream.enumerateFromTo 1 100):}("Even 50","Odd 50")
Pre-release
Similar to partitionByM but terminates when the first fold terminates.
Partition the input over two folds using an Either partitioning predicate.
|-------Fold b x--------|
-----stream m a --> (Either b c)----| |----(x,y)
|-------Fold c y--------|
Example, send input to either fold randomly:
:set -package randomimport System.Random (randomIO)randomly a = randomIO >>= \x -> return $ if x then Left a else Right af = Fold.partitionByM randomly Fold.length Fold.lengthStream.fold f (Stream.enumerateFromTo 1 100)...
Example, send input to the two folds in a proportion of 2:1:
:set -fno-warn-unrecognised-warning-flags:set -fno-warn-x-partial:{proportionately m n = do ref <- newIORef $ cycle $ concat [replicate m Left, replicate n Right] return $ \a -> do r <- readIORef ref writeIORef ref $ tail r return $ Prelude.head r a:}
:{main = do g <- proportionately 2 1 let f = Fold.partitionByM g Fold.length Fold.length r <- Stream.fold f (Stream.enumerateFromTo (1 :: Int) 100) print r:}
main(67,33)
This is the consumer side dual of the producer side mergeBy operation.
When one fold is done, any input meant for it is ignored until the other fold is also done.
Stops when both the folds stop.
See also: partitionByFstM and partitionByMinM.
Pre-release
Similar to partitionByM but terminates when any fold terminates.
Determine the product of all elements of a stream of numbers. Returns
multiplicative identity (1) when the stream is empty. The fold terminates
when it encounters (0) in its input.
Same as the following but terminates on multiplication by 0:
product = fmap Data.Monoid.getProduct $ Fold.foldMap Data.Monoid.ProductStrip all leading and trailing occurrences of an element passing a predicate and make all other consecutive occurrences uniq.
> prune p = Stream.dropWhileAround p $ Stream.uniqBy (x y -> p x && p y)> Stream.prune isSpace (Stream.fromList " hello world! ")
"hello world!"
Space: O(1)
Unimplemented
Find minimum and maximum elements i.e. (min, max).
Emit only repeated elements, once.
Unimplemented
Compute an Int sized polynomial rolling hash of a stream.
rollingHash = Fold.rollingHashWithSalt Fold.defaultSaltCompute an Int sized polynomial rolling hash of the first n elements of a stream.
rollingHashFirstN n = Fold.take n Fold.rollingHashPre-release
Compute an Int sized polynomial rolling hash
H = salt * k ^ n + c1 * k ^ (n - 1) + c2 * k ^ (n - 2) + ... + cn * k ^ 0Where c1, c2, cn are the elements in the input stream and k is a
constant.
This hash is often used in Rabin-Karp string search algorithm.
rollingMap f = Fold.rollingMapM (\x y -> return $ f x y)Apply a function on every two successive elements of a stream. The first argument of the map function is the previous element and the second argument is the current element. When processing the very first element in the stream, the previous element is Nothing.
Pre-release
sampleFromthen offset stride samples the element at offset index and
then every element at strides of stride.
Consume a single element and return it if it passes the predicate else return Nothing.
Definition:
satisfy f = Fold.maybe (\a -> if f a then Just a else Nothing)Pre-release
Semigroup concat. Append the elements of an input stream to a provided starting value.
Definition:
sconcat = Fold.foldl' (<>)semigroups = fmap Data.Monoid.Sum $ Stream.enumerateFromTo 1 10Stream.fold (Fold.sconcat 10) semigroupsSum {getSum = 65}
Deprecated. Use "rmapM id" instead
Flatten the monadic output of a fold to pure output.
Provide a sliding window of length 2 elements.
See Streamly.Internal.Data.Fold.Window.
splitAt n f1 f2 composes folds f1 and f2 such that first n
elements of its input are consumed by fold f1 and the rest of the stream
is consumed by fold f2.
let splitAt_ n xs = Stream.fold (Fold.splitAt n Fold.toList Fold.toList) $ Stream.fromList xssplitAt_ 6 "Hello World!"("Hello ","World!")
splitAt_ (-1) [1,2,3]([],[1,2,3])
splitAt_ 0 [1,2,3]([],[1,2,3])
splitAt_ 1 [1,2,3]([1],[2,3])
splitAt_ 3 [1,2,3]([1,2,3],[])
splitAt_ 4 [1,2,3]([1,2,3],[])
splitAt n f1 f2 = Fold.splitWith (,) (Fold.take n f1) f2Internal
Deprecated. Use the streamly-statistics package instead
Compute a numerically stable (population) standard deviation over all elements in the input stream.
Determine the sum of all elements of a stream of numbers. Returns additive
identity (0) when the stream is empty. Note that this is not numerically
stable for floating point numbers.
sum = Fold.fromScanl (Scanl.cumulativeScan Scanl.incrSum)Same as following but numerically stable:
sum = Fold.foldl' (+) 0sum = fmap Data.Monoid.getSum $ Fold.foldMap Data.Monoid.Sum
Continue taking the input until the input sequence matches the supplied sequence, taking the supplied sequence as well. If the pattern is empty this acts as an identity fold.
s = Stream.fromList "Gauss---Euler---Noether"f = Fold.takeEndBySeq (Array.fromList "---") Fold.toListStream.fold f s"Gauss---"
Stream.fold Fold.toList $ Stream.foldMany f s["Gauss---","Euler---","Noether"]
Uses Rabin-Karp algorithm for substring search.
See also: Streamly.Data.Stream.splitOnSeq and
Streamly.Data.Stream.splitEndBySeq.
Pre-release
Like takeEndBySeq but discards the matched sequence.
s = Stream.fromList "Gauss---Euler---Noether"f = Fold.takeEndBySeq_ (Array.fromList "---") Fold.toListStream.fold f s"Gauss"
Stream.fold Fold.toList $ Stream.foldMany f s["Gauss","Euler","Noether"]
See also: Streamly.Data.Stream.splitOnSeq and
Streamly.Data.Stream.splitEndBySeq_.
Pre-release
takingEndBy p = Fold.takingEndByM (return . p)takingEndBy_ p = Fold.takingEndByM_ (return . p)Distribute one copy of the stream to each fold and zip the results.
|-------Fold m a b--------|
---stream m a---| |---m (b,c)
|-------Fold m a c--------|
Definition:
tee = Fold.teeWith (,)Example:
t = Fold.tee Fold.sum Fold.lengthStream.fold t (Stream.enumerateFromTo 1.0 100.0)(5050.0,100)
A fold that buffers its input to a pure stream.
Warning! working on large streams accumulated as buffers in memory could be very inefficient, consider using Streamly.Data.Array instead.
toStream = fmap Stream.fromList Fold.toListPre-release
Buffers the input stream to a pure stream in the reverse order of the input.
toStreamRev = fmap Stream.fromList Fold.toListRevWarning! working on large streams accumulated as buffers in memory could be very inefficient, consider using Streamly.Data.Array instead.
Pre-release
Fold the input stream to top n elements.
Definition:
top = Fold.topBy comparestream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]Stream.fold (Fold.top 3) stream >>= MutArray.toList[17,11,9]
Pre-release
Get the top n elements using the supplied comparison function.
To get bottom n elements instead:
bottomBy cmp = Fold.topBy (flip cmp)Example:
stream = Stream.fromList [2::Int,7,9,3,1,5,6,11,17]Stream.fold (Fold.topBy compare 3) stream >>= MutArray.toList[17,11,9]
Pre-release
Apply a monadic function to each element flowing through and discard the results.
Stream.fold (Fold.trace print Fold.drain) $ (Stream.enumerateFromTo (1 :: Int) 2)12
trace f = Fold.lmapM (Fold.tracing f)Pre-release
Apply a monadic function on the input and return the input.
Stream.fold (Fold.lmapM (Fold.tracing print) Fold.drain) $ (Stream.enumerateFromTo (1 :: Int) 2)12
Pre-release
Unfold and flatten the input stream of a fold.
Stream.fold (unfoldMany u f) = Stream.fold f . Stream.unfoldMany u
Pre-release
Return the latest unique element using the supplied comparison function. Returns Nothing if the current element is same as the last element otherwise returns Just.
Example, strip duplicate path separators:
input = Stream.fromList "//a//b"f x y = x == '/' && y == '/'
> Stream.toList $ Stream.scanMaybe (Fold.uniqBy f) input"ab"
Space: O(1)
Pre-release
Send the elements of tuples in a stream of tuples through two different folds.
|-------Fold m a x--------|
---------stream of (a,b)--| |----m (x,y)
|-------Fold m b y--------|
Definition:
unzip = Fold.unzipWith idThis is the consumer side dual of the producer side zip operation.
Split elements in the input stream into two parts using a pure splitter function, direct each part to a different fold and zip the results.
Definitions:
unzipWith f = Fold.unzipWithM (return . f)unzipWith f fld1 fld2 = Fold.lmap f (Fold.unzip fld1 fld2)
This fold terminates when both the input folds terminate.
Pre-release
Similar to unzipWithM but terminates when the first fold terminates.
Like unzipWith but with a monadic splitter function.
Definition:
unzipWithM k f1 f2 = Fold.lmapM k (Fold.unzip f1 f2)Pre-release
Similar to unzipWithM but terminates when any fold terminates.
Deprecated. Use the streamly-statistics package instead
Compute a numerically stable (population) variance over all elements in the input stream.
Change the predicate function of a Fold from a -> b to accept an
additional state input (s, a) -> b. Convenient to filter with an
addiitonal index or time input.
filterWithIndex = Fold.with Fold.indexed Fold.filterfilterWithAbsTime = with timestamped filter
filterWithRelTime = with timeIndexed filter
Pre-release
Zip a stream with the input of a fold.
zip = Fold.zipStreamWithM (curry return)Unimplemented
Zip a stream with the input of a fold using the supplied function.
Unimplemented
A default salt used in the implementation of rollingHash.
Deprecated. Use classifyScan instead
Folds the values for each key using the supplied fold. When scanning, as soon as the fold is complete, its result is available in the second component of the tuple. The first component of the tuple is a snapshot of the in-progress folds.
Once the fold for a key is done, any future values of the key are ignored.
Definition:
> classify f fld = Fold.demux f (const fld)Deprecated. Use classifyScanGeneric instead
Deprecated. Use classifyGenericIO from Scanl module
Deprecated. Use classifyScanIO instead
Same as classify except that it uses mutable IORef cells in the Map providing better performance. Be aware that if this is used as a scan, the values in the intermediate Maps would be mutable.
Definitions:
> classifyIO f fld = Fold.demuxIO f (const fld)Scanning variant of toMap.
Scanning variant of toContainer.
Scanning variant of classifyGenericIO.
This is a specialized version of classifyScan that uses mutable IO cells as scan accumulators for better performance.
TODO: To drain the final in-progress folds this requires the drain step of Scanl to be streaming.
Count non-duplicate elements in the stream.
Definition:
countDistinct = fmap Set.size Fold.toSetcountDistinct = Fold.postscanl Scanl.nub $ Fold.catMaybes $ Fold.length
The memory used is proportional to the number of distinct elements in the stream, to guard against using too much memory use it as a scan and terminate if the count reaches more than a threshold.
Space: \mathcal{O}(n)
Pre-release
Like countDistinct but specialized to a stream of Int, for better performance.
Definition:
countDistinctInt = fmap IntSet.size Fold.toIntSetcountDistinctInt = Fold.postscanl Scanl.nubInt $ Fold.catMaybes $ Fold.length
Pre-release
Deprecated. Use demuxScan instead
demux getKey getFold: In a key value stream, fold values corresponding
to each key using a key specific fold. getFold is invoked to generate a
key specific fold when a key is encountered for the first time in the
stream.
The first component of the output tuple is a key-value Map of in-progress folds. The fold returns the fold result as the second component of the output tuple whenever a fold terminates.
If a fold terminates, another instance of the fold is started upon receiving
an input with that key, getFold is invoked again whenever the key is
encountered again.
This can be used to scan a stream and collect the results from the scan output.
Since the fold generator function is monadic we can add folds dynamically. For example, we can maintain a Map of keys to folds in an IORef and lookup the fold from that corresponding to a key. This Map can be changed dynamically, folds for new keys can be added or folds for old keys can be deleted or modified.
Compare with classify, the fold in classify is a static fold.
Pre-release
Deprecated. Use demuxScanGeneric instead
This is the most general of all demux, classify operations.
See demux for documentation.
Deprecated. Use demuxScanGenericIO instead
This is specialized version of demuxGeneric that uses mutable IO cells as fold accumulators for better performance.
Deprecated. Use demuxScanIO instead
This is specialized version of demux that uses mutable IO cells as fold accumulators for better performance.
Keep in mind that the values in the returned Map may be changed by the ongoing fold if you are using those concurrently in another thread.
Fold a stream of key value pairs using a function that maps keys to folds.
Definition:
demuxKvToMap f = Fold.demuxerToContainer fst (Fold.lmap snd . f)Example:
import Data.Map (Map):{ let f "SUM" = return (Just Fold.sum) f _ = return (Just Fold.product) input = Stream.fromList [("SUM",1),("PRODUCT",2),("SUM",3),("PRODUCT",4)] in Stream.fold (Fold.demuxKvToMap f) input :: IO (Map String Int):}fromList [("PRODUCT",8),("SUM",4)]
Pre-release
Scanning variant of demuxerToMap.
TODO: To drain the final in-progress folds this requires the drain step of Scanl to be streaming.
Scanning variant of demuxerToContainer.
This is a specialized version of demux that uses mutable IO cells as fold accumulators for better performance.
Keep in mind that the values in the returned Map may be changed by the ongoing fold if you are using those concurrently in another thread.
This is a specialized version of demuxScan that uses mutable IO cells as scan accumulators for better performance.
TODO: To drain the final in-progress folds this requires the drain step of Scanl to be streaming.
Deprecated. Use demuxerToContainer instead
Deprecated. Use demuxerToContainerIO instead
Deprecated. Use demuxerToMap instead
This collects all the results of demux in a Map.
Deprecated. Use demuxerToMapIO instead
Same as demuxToMap but uses demuxIO for better performance.
This is the most general of all demux, classify operations.
See demux for documentation.
This is a specialized version of demuxToContainer that uses mutable IO cells as fold accumulators for better performance.
demuxerToMap getKey getFold: In a key value stream, fold values
corresponding to each key using a key specific fold. getFold is invoked to
generate a key specific fold when a key is encountered for the first time in
the stream.
If a fold terminates, another instance of the fold is started upon receiving
an input with that key, getFold is invoked again whenever the key is
encountered again.
This combinator can be used to scan a stream and collect the results from the scan output.
Since the fold generator function is monadic, folds for new keys can be added dynamically or folds for old keys can be deleted or modified. For example, we can maintain a Map of keys to folds in an IORef and lookup the fold from that corresponding to a key. This Map can be changed dynamically.
Note that this fold never terminates. Inputs that do not correspond to a fold in the map are dropped.
Compare with classify, the fold in classify is a static fold.
Pre-release
Same as demuxerToMap but uses mutable cells for better performance.
Determine the frequency of each element in the stream.
You can just collect the keys of the resulting map to get the unique elements in the stream.
Definition:
frequency = Fold.toMap id Fold.lengthGiven an input stream of key value pairs and a fold for values, fold all the values belonging to each key. Useful for map/reduce, bucketizing the input in different bins or for generating histograms.
Definition:
kvToMap = Fold.toMap fst . Fold.lmap sndExample:
:{ let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)] in Stream.fold (Fold.kvToMap Fold.toList) input:}fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
Pre-release
Fold the input to an int set. For integer inputs this performs better than toSet.
Definition:
toIntSet = Fold.foldl' (flip IntSet.insert) IntSet.emptySplit the input stream based on a key field and fold each split using the given fold. Useful for map/reduce, bucketizing the input in different bins or for generating histograms.
Example:
import Data.Map.Strict (Map):{ let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)] classify = Fold.toMap fst (Fold.lmap snd Fold.toList) in Stream.fold classify input :: IO (Map String [Double]):}fromList [("ONE",[1.0,1.1]),("TWO",[2.0,2.2])]
Once the classifier fold terminates for a particular key any further inputs in that bucket are ignored.
Space used is proportional to the number of keys seen till now and monotonically increases because it stores whether a key has been seen or not.
See demuxToMap for a more powerful version where you can use a different fold for each key. A simpler version of toMap retaining only the last value for a key can be written as:
toMap = Fold.foldl' (\kv (k, v) -> Map.insert k v kv) Map.emptyStops: never
Pre-release
Same as toMap but maybe faster because it uses mutable cells as fold accumulators in the Map.
Fold the input to a set.
Definition:
toSet = Fold.foldl' (flip Set.insert) Set.emptyConvert an incremental fold to a cumulative fold using the entire input stream as a single window.
cumulative f = Fold.lmap (\x -> (x, Nothing)) fThe number of elements in the rolling window.
This is the 0th power sum.
length = Fold.windowPowerSum 0Map a function on the incoming as well as outgoing element of a rolling window fold.
:set -fno-warn-deprecationslmap f = Fold.lmap (bimap f (f <$>))
The maximum element in a rolling window.
See the performance related comments in minimum.
If you want to compute the maximum of the entire stream Fold.maximum would
be much faster.
Time: \mathcal{O}(n*w) where w is the window size.
Arithmetic mean of elements in a sliding window:
\mu = \frac{\sum_{i=1}^n x_{i}}{n}
This is also known as the Simple Moving Average (SMA) when used in the sliding window and Cumulative Moving Avergae (CMA) when used on the entire stream.
mean = Fold.teeWith (/) Fold.windowSum Fold.windowLengthSpace: \mathcal{O}(1)
Time: \mathcal{O}(n)
Find the minimum element in a rolling window.
This implementation traverses the entire window buffer to compute the
minimum whenever we demand it. It performs better than the dequeue based
implementation in streamly-statistics package when the window size is
small (< 30).
If you want to compute the minimum of the entire stream
Streamly.Data.Fold.minimum is much faster.
Time: \mathcal{O}(n*w) where w is the window size.
Sum of the kth power of all the elements in a rolling window:
S_k = \sum_{i=1}^n x_{i}^k
windowPowerSum k = Fold.windowLmap (^ k) Fold.windowSumSpace: \mathcal{O}(1)
Time: \mathcal{O}(n)
Like powerSum but powers can be negative or fractional. This is slower
than powerSum for positive intergal powers.
windowPowerSumFrac p = Fold.windowLmap (** p) Fold.windowSumDetermine the maximum and minimum in a rolling window.
If you want to compute the range of the entire stream Fold.teeWith (,)
Fold.maximum Fold.minimum would be much faster.
Space: \mathcal{O}(n) where n is the window size.
Time: \mathcal{O}(n*w) where w is the window size.
Apply a pure function on the latest and the oldest element of the window.
windowRollingMap f = Fold.windowRollingMapM (\x y -> return $ f x y)Apply an effectful function on the latest and the oldest element of the window.
Sum of all the elements in a rolling window:
S = \sum_{i=1}^n x_{i}
This is the first power sum.
windowSum = Fold.windowPowerSum 1Uses Kahan-Babuska-Neumaier style summation for numerical stability of floating precision arithmetic.
Space: \mathcal{O}(1)
Time: \mathcal{O}(n)
The sum of all the elements in a rolling window. The input elements are required to be intergal numbers.
This was written in the hope that it would be a tiny bit faster than sum
for Integral values. But turns out that sum is 2% faster than this even
for intergal values!
Internal
Run a side effect before the initialization of the fold.
bracketIO before after between runs before and invokes between using
its output, then runs the fold generated by between. If the fold ends
normally, due to an exception or if it is garbage collected prematurely then
after is run with the output of before as argument.
If before or after throw an exception that exception is thrown.
Run a side effect whenever the fold stops normally, aborts due to an exception or is garbage collected.
onException action fold runs action whenever the fold throws an
exception. The action is executed on any exception whether it is in
initial, step or extract action of the fold.
The exception is not caught, simply rethrown. If the action itself
throws an exception that exception is thrown instead of the original
exception.
Internal