Streamly.Internal.Data.Scanr
Right scans.
Scanr vs Stream
A scan is a generalization of a stream. Like streams, a scan has an internal
state. Unlike a stream, a scan produces an output only on an input, the
output is a function of the scan state and the input. A scan produces at
most one output on one input, in other words it is driven solely by the
input, it cannot produce output on its own. A Scanr m () a
can represent a
Stream m a
by supplying the scan with () inputs.
Scans vs pipes:
A scan is a simpler version of pipes. It can produce at most one output on one input. Whereas a pipe may produce output even without consuming anything or it can produce multiple outputs on a single input. Scans are simpler abstractions to think about compared to pipes and easier for the compiler to optimize and fuse.
Compositions
Append: this is the easiest. The behavior is simple even in presence of filtering (Skip) and termination (Stop). Skip translates to Skip, Stop translates to Stop.
demux: we select one of n scans to run. Behaviour with Skip is straight forward. Termination behavior has multiple options, stop when first one stops, stop when the last one stops, or stop when a selected one stops.
zip: run all and zip the outputs. If one of them Skips we Skip the output. If one of them stops we stop. It may be possible to collect the outputs as Just/Nothing values.
Another option could be if a Scan terminates do we want to start it again or not.
Type
Represents a stateful transformation over an input stream of values of
type a
to outputs of type b
in Monad
m
.
The constructor is Scan consume initial
.
Instances
Monad m => Category (Scanr m :: Type -> Type -> Type) Source # | |
Monad m => Arrow (Scanr m) Source # | |
Defined in Streamly.Internal.Data.Scanr | |
Monad m => Applicative (Scanr m a) Source # | Zips the outputs only when both scans produce outputs, discards otherwise. |
Defined in Streamly.Internal.Data.Scanr Methods pure :: a0 -> Scanr m a a0 Source # (<*>) :: Scanr m a (a0 -> b) -> Scanr m a a0 -> Scanr m a b Source # liftA2 :: (a0 -> b -> c) -> Scanr m a a0 -> Scanr m a b -> Scanr m a c Source # (*>) :: Scanr m a a0 -> Scanr m a b -> Scanr m a b Source # (<*) :: Scanr m a a0 -> Scanr m a b -> Scanr m a a0 Source # | |
Functor m => Functor (Scanr m a) Source # |
|
Primitive Scans
identity :: Monad m => Scanr m a a Source #
An identity scan producing the same output as input.
>>>
identity = Scanr.function Prelude.id
>>>
Stream.toList $ Stream.scanr (Scanr.identity) $ Stream.fromList [1..5::Int]
[1,2,3,4,5]
function :: Monad m => (a -> b) -> Scanr m a b Source #
A scan representing mapping of a pure function.
>>>
Stream.toList $ Stream.scanr (Scanr.function (+1)) $ Stream.fromList [1..5::Int]
[2,3,4,5,6]
functionM :: Monad m => (a -> m b) -> Scanr m a b Source #
A scan representing mapping of a monadic action.
>>>
Stream.toList $ Stream.scanr (Scanr.functionM print) $ Stream.fromList [1..5::Int]
1 2 3 4 5 [(),(),(),(),()]
filter :: Monad m => (a -> Bool) -> Scanr m a a Source #
A filtering scan using a pure predicate.
>>>
Stream.toList $ Stream.scanr (Scanr.filter odd) $ Stream.fromList [1..5::Int]
[1,3,5]
filterM :: Monad m => (a -> m Bool) -> Scanr m a a Source #
A filtering scan using a monadic predicate.
Combinators
compose :: Monad m => Scanr m b c -> Scanr m a b -> Scanr m a c Source #
Connect two scans in series. Attach the first scan on the output of the second scan.
>>>
import Control.Category
>>>
Stream.toList $ Stream.scanr (Scanr.function (+1) >>> Scanr.function (+1)) $ Stream.fromList [1..5::Int]
[3,4,5,6,7]
teeWithMay :: Monad m => (Maybe b -> Maybe c -> d) -> Scanr m a b -> Scanr m a c -> Scanr m a d Source #
Connect two scans in parallel. Distribute the input across two scans and
zip their outputs. If the scan filters the output, Nothing
is emitted
otherwise Just
is emitted. The scan stops if any of the scans stop.
>>>
Stream.toList $ Stream.scanr (Scanr.teeWithMay (,) Scanr.identity (Scanr.function (\x -> x * x))) $ Stream.fromList [1..5::Int]
[(Just 1,Just 1),(Just 2,Just 4),(Just 3,Just 9),(Just 4,Just 16),(Just 5,Just 25)]
teeWith :: Monad m => (b -> c -> d) -> Scanr m a b -> Scanr m a c -> Scanr m a d Source #
Produces an output only when both the scans produce an output. If any of the scans skips the output then the composed scan also skips. Stops when any of the scans stop.
>>>
Stream.toList $ Stream.scanr (Scanr.teeWith (,) Scanr.identity (Scanr.function (\x -> x * x))) $ Stream.fromList [1..5::Int]
[(1,1),(2,4),(3,9),(4,16),(5,25)]