Loading...

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

data Scanr m a b Source #

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.

Constructors

forall s. Scanr (s -> a -> m (Step s b)) s 
Instances
Instances details
Monad m => Category (Scanr m :: Type -> Type -> Type) Source # 
Instance details

Defined in Streamly.Internal.Data.Scanr

Methods

id :: forall (a :: k). Scanr m a a Source #

(.) :: forall (b :: k) (c :: k) (a :: k). Scanr m b c -> Scanr m a b -> Scanr m a c Source #

Monad m => Arrow (Scanr m) Source # 
Instance details

Defined in Streamly.Internal.Data.Scanr

Methods

arr :: (b -> c) -> Scanr m b c Source #

first :: Scanr m b c -> Scanr m (b, d) (c, d) Source #

second :: Scanr m b c -> Scanr m (d, b) (d, c) Source #

(***) :: Scanr m b c -> Scanr m b' c' -> Scanr m (b, b') (c, c') Source #

(&&&) :: Scanr m b c -> Scanr m b c' -> Scanr m b (c, c') Source #

Monad m => Applicative (Scanr m a) Source #

Zips the outputs only when both scans produce outputs, discards otherwise.

Instance details

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 #

fmap maps a pure function on a scan output.

>>> Stream.toList $ Stream.scanr (fmap (+1) Scanr.identity) $ Stream.fromList [1..5::Int]
[2,3,4,5,6]
Instance details

Defined in Streamly.Internal.Data.Scanr

Methods

fmap :: (a0 -> b) -> Scanr m a a0 -> Scanr m a b Source #

(<$) :: a0 -> Scanr m a b -> Scanr m a a0 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)]

tee :: Monad m => Scanr m a b -> Scanr m a c -> Scanr m a (b, c) Source #

Scans

sum :: (Monad m, Num a) => Scanr m a a Source #