Module

Hareactive.Combinators

Package
purescript-hareactive
Repository
funkia/purescript-hareactive

This module contains all the combinators in Hareactive.

The lists below contains convenient grouping of various functions.

Accumulating state

accum :: (a -> b -> b) -> b -> Stream a -> Now (Behavior b) scan :: (a -> b -> b) -> b -> Stream a -> Now (Stream b) integrate :: Behavior Number -> Now (Behavior Number)

Stepping and switching

The term "switch" refers to a behavior that changes between one or more behaviors. The term "step" refers to a behavior changes between constants. In other words, "switch" is a generalization of "step" that one arrives at by replacing a with Behavior a.

stepTo :: a -> Future a -> Behavior a switchTo :: Behavior a -> Future (Behavior a) -> Behavior a stepper :: a -> Stream a -> Now (Behavior a) switcher :: Behavior a -> Stream (Behavior a) -> Now (Behavior a)

Shifts

The term "shift" refers to creating a stream that changes between one or more streams.

  • shiftCurrent :: Behavior (Stream a) -> Stream a
  • shift :: Stream (Stream a) -> Now (Stream a)

Converting between reactive values

Flattening nested reactive values.

#applyS Source

applyS :: forall a b. Behavior (a -> b) -> Stream a -> Stream b

This function is similar to apply for behaviors except the last argument is a stream instead of a behaviors. Whenever the stream has an occurrence the function at the behavior is applied to the value of the occurrence.

This function has an operator alias <~>. The operator is intended to work in tandem with <$> and <*>. As an example, assume that f3 is a function of three arguments, that b1 and b2 are two behaviors, and that s is a stream.` Then the function can be applied to the two behaviors and the stream in the following way.

f3 <$> b1 <*> b2 <~> s

With the above code, whenever s has an occurrence the value of b1, b2, and the value of the occurrence will be applied to f3 and its return value will be the value of the occurrence in the resulting stream.

Semantically.

applyS b s = map (\{time, a} -> {time, a: (b time) a}) s

#(<~>) Source

Operator alias for Control.Apply.apply (left-associative / precedence 4)

#filterApply Source

filterApply :: forall a. Behavior (a -> Boolean) -> Stream a -> Stream a

A combination of filter and apply. For each occurrence of the stream the predicate at the behavior at that time is applied to the value and the returned stream contains the occurrence if and only if the predicate returns true.

This function can be seen as a generalization of filter. Where filter takes a constant predicate function filterApply takes a varying predicate in the form of a behavior of a predicate. As such filterApply (pure predicate) stream is equivalent to filter predicate stream.

#filter Source

filter :: forall a. (a -> Boolean) -> Stream a -> Stream a

Filter a stream, keeping the elements which satisfy a predicate function, creating a new stream.

Semantically.

filter p s = filter (\(time, a) -> p x) s

#filterJust Source

filterJust :: forall a. Stream (Maybe a) -> Stream a

Removes all Nothing values from the stream and extracts the values from the remaining Justs.

#split Source

split :: forall a. (a -> Boolean) -> Stream a -> { fail :: Stream a, pass :: Stream a }

Takes a predicate and a stream. A record of to streams is returned. The first stream includes all occurrences from the original stream which pass the predicate test and the second stream includes all occurrences which fail to pass the predicate.

{ pass: smallNumbers, fail: largeNumbers } = split (_ < 100) streamOfNumbers

#keepWhen Source

keepWhen :: forall a. Stream a -> Behavior Boolean -> Stream a

Filter a stream, keeping the elements which satisfy a predicate function, creating a new stream.

keepWhen s b = filter (\{time, a} -> b time) s

#sample Source

sample :: forall a. Behavior a -> Now a

Returns the current value of the behavior in the Now. This is possible because computations in the Now monad have an associated point in time.

#snapshot Source

snapshot :: forall a b. Behavior a -> Stream b -> Stream a

Creates a stream that occurs exactly when the given stream occurs. Every time the stream s has an occurrence the current value of the behavior is sampled. The value in the occurrence is then replaced with the sampled value.

#snapshotWith Source

snapshotWith :: forall a b c. (a -> b -> c) -> Behavior b -> Stream a -> Stream c

Returns a stream that occurs whenever the given stream occurs. At each occurrence the value and the value from the behavior is passed to the function and the return value is the value of the returned streams occurrence.

#selfie Source

selfie :: forall a. Stream (Behavior a) -> Stream a

On each occurrence the behavior is sampled at the time of the occurrence.

#accum Source

accum :: forall a b. (a -> b -> b) -> b -> Stream a -> Now (Behavior b)

For each occurrence on the stream the function is applied to the value and the accumulator.

#accumFrom Source

accumFrom :: forall a b. (a -> b -> b) -> b -> Stream a -> Behavior (Behavior b)

Generalization of accum satisfying the equation accum f init s = sample $ accumFrom f init s.

Semantically.

accumFrom f a s =
  \from, to -> foldr f a <<< map (_.a) <<< filter ({time} -> from <= time && to <= endT) $ s

#scan Source

scan :: forall a b. (a -> b -> b) -> b -> Stream a -> Now (Stream b)

Similar to accum but instead of returning a behavior it returns a stream.

#scanFrom Source

scanFrom :: forall a b. (a -> b -> b) -> b -> Stream a -> Behavior (Stream b)

Generalization of scan satisfying the equation scan f init s = sample $ scanFrom f init s.

#stepTo Source

stepTo :: forall a. a -> Future a -> Behavior a

From an initial value and a future value, stepTo creates a new behavior that has the initial value until next occurs, after which it has the value of the future.

#stepper Source

stepper :: forall a. a -> Stream a -> Now (Behavior a)

Creates a behavior whose value is the last occurrence in the stream.

#stepperFrom Source

stepperFrom :: forall a. a -> Stream a -> Behavior (Behavior a)

Generalization of stepper satisfying stepper init s = sample $ stepperFrom init s.

#switchTo Source

switchTo :: forall a. Behavior a -> Future (Behavior a) -> Behavior a

Creates a new behavior that acts exactly like the first behavior until the future occurs after which it acts like the behavior from the future.

#switcher Source

switcher :: forall a. Behavior a -> Stream (Behavior a) -> Now (Behavior a)

Creates a behavior that initially acts like the first behavior and then switches to each new behavior from the stream.

This function is equal to switcherB >>> sample

#switcherFrom Source

switcherFrom :: forall a. Behavior a -> Stream (Behavior a) -> Behavior (Behavior a)

Creates a behavior that initially acts like the first behavior and then switches to each new behavior from the stream.

#shiftCurrent Source

shiftCurrent :: forall a. Behavior (Stream a) -> Stream a

Takes a stream valued behavior and returns a stream that emits values from the current stream at the behavior. I.e. the returned stream always "shifts" to the current stream at the behavior.

#shift Source

shift :: forall a. Stream (Stream a) -> Now (Stream a)

Takes a stream of a stream and returns a stream that emits from the last stream.

#shiftFrom Source

shiftFrom :: forall a. Stream (Stream a) -> Behavior (Stream a)

Takes a stream of a stream and returns a stream that emits from the last stream.

#time Source

time :: Behavior Number

A behavior whose value is the number of milliseconds elapsed since UNIX epoch.

#measureTime Source

measureTime :: Now (Behavior Number)

The now-computation results in a behavior that tracks the time passed since its creation.

#measureTimeFrom Source

measureTimeFrom :: Behavior (Behavior Number)

A behavior giving access to continous time. When sampled the outer behavior returns a behavior whose value is the time since the outer behavior was sampled.

Semantically.

measureTimeFrom = \from, to -> to - from

#changes Source

changes :: forall a. Eq a => Behavior a -> Stream a

Takes a behavior and returns a stream that has an occurrence whenever the behavior changes.

#toggle Source

toggle :: forall a b. Boolean -> Stream a -> Stream b -> Now (Behavior Boolean)

Creates a behavior that switches between true and false. Initally it takes the value of its first argument. Each occurrence of the first stream will make the behavior true and each occurrence of the second stream makes the behavior false.

The example below demonstrates one use case for toggle. A stream doorOpen signifies that a door has been opened and similairly a stream doorClose signifies that the door has closed. toggle is then used to construct a behavior that at any time represents the state of the door.

isDoorOpen <- toggle false doorOpen doorClose

#toggleFrom Source

toggleFrom :: forall a b. Boolean -> Stream a -> Stream b -> Behavior (Behavior Boolean)

Generalization of toggle satisfying toggle initial on off = sample $ toggleB initial on off.

#moment Source

moment :: forall b. ((forall a. Behavior a -> a) -> b) -> Behavior b

#nextOccurrence Source

nextOccurrence :: forall a. Stream a -> Now (Future a)

Returns the next occurrence at the stream as a future.

#nextOccurrenceFrom Source

nextOccurrenceFrom :: forall a. Stream a -> Behavior (Future a)

Returns the next occurrence at the stream as a future.

#integrate Source

integrate :: Behavior Number -> Now (Behavior Number)

Integrate behavior with respect to time. The value of the given behavior is interpreted as being a rate of change per second.

Note that integrate is implemented using Euler's method. Hence the resulting behavior is not exact but includes some numerical error.

#integrateFrom Source

integrateFrom :: Behavior Number -> Behavior (Behavior Number)

Generalization of integrate satisfying integrate = sample <<< integrateFrom.

#logS Source

logS :: forall a. String -> Stream a -> Effect Unit

console.logs the value of every occurrence.

#logB Source

logB :: forall a. String -> Behavior a -> Effect Unit

console.logs the value of the behavior whenever it changes.

#runAffNow Source

runAffNow :: forall a. Aff a -> Now (Future (Either Error a))

Runs an Aff inside a Now-computation.

#runFutureEffect Source

runFutureEffect :: forall a. Future (Effect a) -> Now (Future a)

Takes a future effect and returns a now-computation that runs the effect once the future occurs and delivers the result in a future.

#runStreamEffect Source

runStreamEffect :: forall a. Stream (Effect a) -> Now (Stream a)

Takes a stream of effects and returns a now-computation that runs the effect in each occurrence and delivers the result in a stream.

#runStreamAff Source

runStreamAff :: forall a. Stream (Aff a) -> Now (Stream (Either Error a))

Takes a stream of Aff and runs each side-effect. The returned stream has an occurrence for the result from each asynchronous computation.

#loopNow Source

loopNow :: forall a. (a -> Now a) -> Now a

Creates a Now-computation that can depend recursively on its own.

The type variable a must be a record consisting of only Future, Stream, or Behavior values. This constraint is not, yet, enforced at the type level.

The counter function in the following contrieved example returns a behavior. Whenever the given stream has an occurrence the counter is increased by adding its current value to a snapshot of its current value.

counter :: forall a. Stream a -> Stream Integer
counter stream = loopNow f
  where f { count } = do
    let countS = snapshot count stream
    count <- accum (+) 1 countS
    pure { count }

#runNow Source

runNow :: forall a. Now a -> Effect a

Returns an Effect that executes the Now computation.