active-0.2.0.18: Abstractions for animation

Copyright | (c) 2011 Brent Yorgey
License | BSD-style (see LICENSE)
Maintainer | byorgey@cis.upenn.edu
Safe Haskell | Safe-Inferred
Language | Haskell2010

Data.Active

Contents

- Representing time
  - Time and duration
  - Eras
- Dynamic values
- Active values
- Combinators
  - Special active values
  - Transforming active values
  - Working with values outside the era
  - Composing active values
- Discretization

Description

Inspired by the work of Kevin Matlage and Andy Gill (Every Animation Should Have a Beginning, a Middle, and an End, Trends in Functional Programming, 2010. http://ku-fpg.github.io/files/Matlage-10-BeginningMiddleEnd.pdf), this module defines a simple abstraction for working with time-varying values. A value of type `Active a` is either a constant value of type `a`, or a time-varying value of type `a` (i.e. a function from time to `a`) with specific start and end times. Since active values have start and end times, they can be aligned, sequenced, stretched, or reversed.

In a sense, this is sort of like a stripped-down version of functional reactive programming (FRP), without the reactivity.

The original motivating use for this library is to support making animations with the diagrams framework (https://diagrams.github.io), but the hope is that it may find more general utility.

There are two basic ways to create an `Active` value. The first is to use `mkActive` to create one directly, by specifying a start and end time and a function of time. More indirectly, one can use the `Applicative` instance together with the unit interval `ui`, which takes on values from the unit interval from time 0 to time 1, or `interval`, which creates an active over an arbitrary interval.

For example, to create a value of type `Active Double` which represents one period of a sine wave starting at time 0 and ending at time 1, we could write

    mkActive 0 1 (\t -> sin (fromTime t * tau))

or

    (sin . (*tau)) <$> ui

`pure` can also be used to create `Active` values which are constant and have no start or end time. For example,

    mod <$> (floor <$> interval 0 100) <*> pure 7

cycles repeatedly through the numbers 0-6.

Note that the "idiom bracket" notation supported by the SHE preprocessor (http://personal.cis.strath.ac.uk/~conor/pub/she/, http://hackage.haskell.org/package/she) can make for somewhat more readable `Applicative` code. For example, the above example can be rewritten using SHE as

    {-# OPTIONS_GHC -F -pgmF she #-}

    ... (| mod (| floor (interval 0 100) |) ~7 |)

There are many functions for transforming and composing active values; see the documentation below for more details.

With careful handling, this module should be suitable to generating deep embeddings if `Active` values.

Synopsis

- data Time n
- toTime :: n -> Time n
- fromTime :: Time n -> n
- data Duration n
- toDuration :: n -> Duration n
- fromDuration :: Duration n -> n
- data Era n
- mkEra :: Time n -> Time n -> Era n
- start :: Era n -> Time n
- end :: Era n -> Time n
- duration :: Num n => Era n -> Duration n
- data Dynamic a = Dynamic {
  - era :: Era Rational
  - runDynamic :: Time Rational -> a
  }
- mkDynamic :: Time Rational -> Time Rational -> (Time Rational -> a) -> Dynamic a
- onDynamic :: (Time Rational -> Time Rational -> (Time Rational -> a) -> b) -> Dynamic a -> b
- shiftDynamic :: Duration Rational -> Dynamic a -> Dynamic a
- data Active a
- mkActive :: Time Rational -> Time Rational -> (Time Rational -> a) -> Active a
- fromDynamic :: Dynamic a -> Active a
- isConstant :: Active a -> Bool
- isDynamic :: Active a -> Bool
- onActive :: (a -> b) -> (Dynamic a -> b) -> Active a -> b
- modActive :: (a -> b) -> (Dynamic a -> Dynamic b) -> Active a -> Active b
- runActive :: Active a -> Time Rational -> a
- activeEra :: Active a -> Maybe (Era Rational)
- setEra :: Era Rational -> Active a -> Active a
- atTime :: Time Rational -> Active a -> Active a
- activeStart :: Active a -> a
- activeEnd :: Active a -> a
- ui :: Fractional a => Active a
- interval :: Fractional a => Time Rational -> Time Rational -> Active a
- stretch :: Rational -> Active a -> Active a
- stretchTo :: Duration Rational -> Active a -> Active a
- during :: Active a -> Active a -> Active a
- shift :: Duration Rational -> Active a -> Active a
- backwards :: Active a -> Active a
- snapshot :: Time Rational -> Active a -> Active a
- clamp :: Active a -> Active a
- clampBefore :: Active a -> Active a
- clampAfter :: Active a -> Active a
- trim :: Monoid a => Active a -> Active a
- trimBefore :: Monoid a => Active a -> Active a
- trimAfter :: Monoid a => Active a -> Active a
- after :: Active a -> Active a -> Active a
- (->>) :: Semigroup a => Active a -> Active a -> Active a
- (|>>) :: Active a -> Active a -> Active a
- movie :: [Active a] -> Active a
- discrete :: [a] -> Active a
- simulate :: Rational -> Active a -> [a]

# Representing time

## Time and duration

data Time n Source #

An abstract type for representing points in time. Note that literal numeric values may be used as `Time`s, thanks to the the `Num` and `Fractional` instances.

#### Instances

Instances details

Functor Time Source # |
Instance details Defined in Data.Active Methods fmap :: (a -> b) -> Time a -> Time b Source # (<$) :: a -> Time b -> Time a Source #
Affine Time Source # |
Instance details Defined in Data.Active Associated Types type Diff Time :: Type -> Type Source # Methods (.-.) :: Num a => Time a -> Time a -> Diff Time a Source # (.+^) :: Num a => Time a -> Diff Time a -> Time a Source # (.-^) :: Num a => Time a -> Diff Time a -> Time a Source #
Enum n => Enum (Time n) Source # |
Instance details Defined in Data.Active Methods succ :: Time n -> Time n Source # pred :: Time n -> Time n Source # toEnum :: Int -> Time n Source # fromEnum :: Time n -> Int Source # enumFrom :: Time n -> [Time n] Source # enumFromThen :: Time n -> Time n -> [Time n] Source # enumFromTo :: Time n -> Time n -> [Time n] Source # enumFromThenTo :: Time n -> Time n -> Time n -> [Time n] Source #
Num n => Num (Time n) Source # |
Instance details Defined in Data.Active Methods (+) :: Time n -> Time n -> Time n Source # (-) :: Time n -> Time n -> Time n Source # (*) :: Time n -> Time n -> Time n Source # negate :: Time n -> Time n Source # abs :: Time n -> Time n Source # signum :: Time n -> Time n Source # fromInteger :: Integer -> Time n Source #
Read n => Read (Time n) Source # |
Instance details Defined in Data.Active Methods readsPrec :: Int -> ReadS (Time n) Source # readList :: ReadS [Time n] Source # readPrec :: ReadPrec (Time n) Source # readListPrec :: ReadPrec [Time n] Source #
Fractional n => Fractional (Time n) Source # |
Instance details Defined in Data.Active Methods (/) :: Time n -> Time n -> Time n Source # recip :: Time n -> Time n Source # fromRational :: Rational -> Time n Source #
Real n => Real (Time n) Source # |
Instance details Defined in Data.Active Methods toRational :: Time n -> Rational Source #
RealFrac n => RealFrac (Time n) Source # |
Instance details Defined in Data.Active Methods properFraction :: Integral b => Time n -> (b, Time n) Source # truncate :: Integral b => Time n -> b Source # round :: Integral b => Time n -> b Source # ceiling :: Integral b => Time n -> b Source # floor :: Integral b => Time n -> b Source #
Show n => Show (Time n) Source # |
Instance details Defined in Data.Active Methods showsPrec :: Int -> Time n -> ShowS Source # show :: Time n -> String Source # showList :: [Time n] -> ShowS Source #
Eq n => Eq (Time n) Source # |
Instance details Defined in Data.Active Methods (==) :: Time n -> Time n -> Bool Source # (/=) :: Time n -> Time n -> Bool Source #
Ord n => Ord (Time n) Source # |
Instance details Defined in Data.Active Methods compare :: Time n -> Time n -> Ordering Source # (<) :: Time n -> Time n -> Bool Source # (<=) :: Time n -> Time n -> Bool Source # (>) :: Time n -> Time n -> Bool Source # (>=) :: Time n -> Time n -> Bool Source # max :: Time n -> Time n -> Time n Source # min :: Time n -> Time n -> Time n Source #
Wrapped (Time n) Source # |
Instance details Defined in Data.Active Associated Types type Unwrapped (Time n) Source # Methods _Wrapped' :: Iso' (Time n) (Unwrapped (Time n)) Source #
Time n1 ~ t => Rewrapped (Time n2) t Source # |
Instance details Defined in Data.Active
type Diff Time Source # |
Instance details Defined in Data.Active type Diff Time = Duration
type Unwrapped (Time n) Source # |
Instance details Defined in Data.Active type Unwrapped (Time n) = n

toTime :: n -> Time n Source #

A convenient wrapper function to convert a numeric value into a time.

fromTime :: Time n -> n Source #

A convenient unwrapper function to turn a time into a numeric value.

data Duration n Source #

An abstract type representing elapsed time between two points in time. Note that durations can be negative. Literal numeric values may be used as `Duration`s thanks to the `Num` and `Fractional` instances.

#### Instances

Instances details

Applicative Duration Source # |
Instance details Defined in Data.Active Methods pure :: a -> Duration a Source # (<*>) :: Duration (a -> b) -> Duration a -> Duration b Source # liftA2 :: (a -> b -> c) -> Duration a -> Duration b -> Duration c Source # (*>) :: Duration a -> Duration b -> Duration b Source # (<*) :: Duration a -> Duration b -> Duration a Source #
Functor Duration Source # |
Instance details Defined in Data.Active Methods fmap :: (a -> b) -> Duration a -> Duration b Source # (<$) :: a -> Duration b -> Duration a Source #
Additive Duration Source # |

Instance details

Defined in Data.Active

Methods

zero :: Num a => Duration a Source #

(^+^) :: Num a => Duration a -> Duration a -> Duration a Source #

(^-^) :: Num a => Duration a -> Duration a -> Duration a Source #

lerp :: Num a => a -> Duration a -> Duration a -> Duration a Source #

liftU2 :: (a -> a -> a) -> Duration a -> Duration a -> Duration a Source #

liftI2 :: (a -> b -> c) -> Duration a -> Duration b -> Duration c Source #

Num n => Monoid (Duration n) Source # |
Instance details Defined in Data.Active Methods mempty :: Duration n Source # mappend :: Duration n -> Duration n -> Duration n Source # mconcat :: [Duration n] -> Duration n Source #
Num n => Semigroup (Duration n) Source # |
Instance details Defined in Data.Active Methods (<>) :: Duration n -> Duration n -> Duration n Source # sconcat :: NonEmpty (Duration n) -> Duration n Source # stimes :: Integral b => b -> Duration n -> Duration n Source #
Enum n => Enum (Duration n) Source # |

Instance details

Defined in Data.Active

Methods

succ :: Duration n -> Duration n Source #

pred :: Duration n -> Duration n Source #

toEnum :: Int -> Duration n Source #

fromEnum :: Duration n -> Int Source #

enumFrom :: Duration n -> [Duration n] Source #

enumFromThen :: Duration n -> Duration n -> [Duration n] Source #

enumFromTo :: Duration n -> Duration n -> [Duration n] Source #

enumFromThenTo :: Duration n -> Duration n -> Duration n -> [Duration n] Source #

Num n => Num (Duration n) Source # |
Instance details Defined in Data.Active Methods (+) :: Duration n -> Duration n -> Duration n Source # (-) :: Duration n -> Duration n -> Duration n Source # (*) :: Duration n -> Duration n -> Duration n Source # negate :: Duration n -> Duration n Source # abs :: Duration n -> Duration n Source # signum :: Duration n -> Duration n Source # fromInteger :: Integer -> Duration n Source #
Read n => Read (Duration n) Source # |
Instance details Defined in Data.Active Methods readsPrec :: Int -> ReadS (Duration n) Source # readList :: ReadS [Duration n] Source # readPrec :: ReadPrec (Duration n) Source # readListPrec :: ReadPrec [Duration n] Source #
Fractional n => Fractional (Duration n) Source # |
Instance details Defined in Data.Active Methods (/) :: Duration n -> Duration n -> Duration n Source # recip :: Duration n -> Duration n Source # fromRational :: Rational -> Duration n Source #
Real n => Real (Duration n) Source # |
Instance details Defined in Data.Active Methods toRational :: Duration n -> Rational Source #
RealFrac n => RealFrac (Duration n) Source # |
Instance details Defined in Data.Active Methods properFraction :: Integral b => Duration n -> (b, Duration n) Source # truncate :: Integral b => Duration n -> b Source # round :: Integral b => Duration n -> b Source # ceiling :: Integral b => Duration n -> b Source # floor :: Integral b => Duration n -> b Source #
Show n => Show (Duration n) Source # |
Instance details Defined in Data.Active Methods showsPrec :: Int -> Duration n -> ShowS Source # show :: Duration n -> String Source # showList :: [Duration n] -> ShowS Source #
Eq n => Eq (Duration n) Source # |
Instance details Defined in Data.Active Methods (==) :: Duration n -> Duration n -> Bool Source # (/=) :: Duration n -> Duration n -> Bool Source #
Ord n => Ord (Duration n) Source # |

Instance details

Defined in Data.Active

Methods

compare :: Duration n -> Duration n -> Ordering Source #

(<) :: Duration n -> Duration n -> Bool Source #

(<=) :: Duration n -> Duration n -> Bool Source #

(>) :: Duration n -> Duration n -> Bool Source #

(>=) :: Duration n -> Duration n -> Bool Source #

max :: Duration n -> Duration n -> Duration n Source #

min :: Duration n -> Duration n -> Duration n Source #

Wrapped (Duration n) Source # |
Instance details Defined in Data.Active Associated Types type Unwrapped (Duration n) Source # Methods _Wrapped' :: Iso' (Duration n) (Unwrapped (Duration n)) Source #
Duration n1 ~ t => Rewrapped (Duration n2) t Source # |
Instance details Defined in Data.Active
type Unwrapped (Duration n) Source # |
Instance details Defined in Data.Active type Unwrapped (Duration n) = n

toDuration :: n -> Duration n Source #

A convenient wrapper function to convert a numeric value into a duration.

fromDuration :: Duration n -> n Source #

A convenient unwrapper function to turn a duration into a numeric value.

## Eras

data Era n Source #

An `Era` is a concrete span of time, that is, a pair of times representing the start and end of the era. `Era`s form a semigroup: the combination of two `Era`s is the smallest `Era` which contains both. They do not form a `Monoid`, since there is no `Era` which acts as the identity with respect to this combining operation.

`Era` is abstract. To construct `Era` values, use `mkEra`; to deconstruct, use `start` and `end`.

#### Instances

Instances details

Ord n => Semigroup (Era n) Source # |
Instance details Defined in Data.Active Methods (<>) :: Era n -> Era n -> Era n Source # sconcat :: NonEmpty (Era n) -> Era n Source # stimes :: Integral b => b -> Era n -> Era n Source #
Show n => Show (Era n) Source # |
Instance details Defined in Data.Active Methods showsPrec :: Int -> Era n -> ShowS Source # show :: Era n -> String Source # showList :: [Era n] -> ShowS Source #

mkEra :: Time n -> Time n -> Era n Source #

Create an `Era` by specifying start and end `Time`s.

start :: Era n -> Time n Source #

Get the start `Time` of an `Era`.

end :: Era n -> Time n Source #

Get the end `Time` of an `Era`.

duration :: Num n => Era n -> Duration n Source #

Compute the `Duration` of an `Era`.

# Dynamic values

data Dynamic a Source #

A `Dynamic a` can be thought of as an `a` value that changes over the course of a particular `Era`. It's envisioned that `Dynamic` will be mostly an internal implementation detail and that `Active` will be most commonly used. But you never know what uses people might find for things.

Constructors

Dynamic |

Fields

- era :: Era Rational
- runDynamic :: Time Rational -> a

#### Instances

Instances details

Functor Dynamic Source # |
Instance details Defined in Data.Active Methods fmap :: (a -> b) -> Dynamic a -> Dynamic b Source # (<$) :: a -> Dynamic b -> Dynamic a Source #

Apply Dynamic Source #

`Dynamic` is an instance of `Apply` (i.e. `Applicative` without `pure`): a time-varying function is applied to a time-varying value pointwise; the era of the result is the combination of the function and value eras. Note, however, that `Dynamic` is not an instance of `Applicative` since there is no way to implement `pure`: the era would have to be empty, but there is no such thing as an empty era (that is, `Era` is not an instance of `Monoid`).

Instance details Defined in Data.Active Methods (<.>) :: Dynamic (a -> b) -> Dynamic a -> Dynamic b Source # (.>) :: Dynamic a -> Dynamic b -> Dynamic b Source # (<.) :: Dynamic a -> Dynamic b -> Dynamic a Source # liftF2 :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c Source #
Semigroup a => Semigroup (Dynamic a) Source # | ``Dynamic` a` is a `Semigroup` whenever `a` is: the eras are combined according to their semigroup structure, and the values of type `a` are combined pointwise. Note that ``Dynamic` a` cannot be an instance of `Monoid` since `Era` is not.
Instance details Defined in Data.Active Methods (<>) :: Dynamic a -> Dynamic a -> Dynamic a Source # sconcat :: NonEmpty (Dynamic a) -> Dynamic a Source # stimes :: Integral b => b -> Dynamic a -> Dynamic a Source #

mkDynamic :: Time Rational -> Time Rational -> (Time Rational -> a) -> Dynamic a Source #

Create a `Dynamic` from a start time, an end time, and a time-varying value.

onDynamic :: (Time Rational -> Time Rational -> (Time Rational -> a) -> b) -> Dynamic a -> b Source #

Fold for `Dynamic`.

shiftDynamic :: Duration Rational -> Dynamic a -> Dynamic a Source #

Shift a `Dynamic` value by a certain duration.

# Active values

For working with time-varying values, it is convenient to have an `Applicative` instance: `<*>` lets us apply time-varying functions to time-varying values; `pure` allows treating constants as time-varying values which do not vary. However, as explained in its documentation, `Dynamic` cannot be made an instance of `Applicative` since there is no way to implement `pure`. The problem is that all `Dynamic` values must have a finite start and end time. The solution is to adjoin a special constructor for pure/constant values with no start or end time, giving us `Active`.

data Active a Source #

There are two types of `Active` values:

- An `Active` can simply be a `Dynamic`, that is, a time-varying value with start and end times.
- An `Active` value can also be a constant: a single value, constant across time, with no start and end times.

The addition of constant values enable `Monoid` and `Applicative` instances for `Active`.

#### Instances

Instances details

Applicative Active Source # |
Instance details Defined in Data.Active Methods pure :: a -> Active a Source # (<*>) :: Active (a -> b) -> Active a -> Active b Source # liftA2 :: (a -> b -> c) -> Active a -> Active b -> Active c Source # (*>) :: Active a -> Active b -> Active b Source # (<*) :: Active a -> Active b -> Active a Source #
Functor Active Source # |
Instance details Defined in Data.Active Methods fmap :: (a -> b) -> Active a -> Active b Source # (<$) :: a -> Active b -> Active a Source #
Apply Active Source # |
Instance details Defined in Data.Active Methods (<.>) :: Active (a -> b) -> Active a -> Active b Source # (.>) :: Active a -> Active b -> Active b Source # (<.) :: Active a -> Active b -> Active a Source # liftF2 :: (a -> b -> c) -> Active a -> Active b -> Active c Source #
(Monoid a, Semigroup a) => Monoid (Active a) Source # |
Instance details Defined in Data.Active Methods mempty :: Active a Source # mappend :: Active a -> Active a -> Active a Source # mconcat :: [Active a] -> Active a Source #
Semigroup a => Semigroup (Active a) Source # | Active values over a type with a `Semigroup` instance are also an instance of `Semigroup`. Two active values are combined pointwise; the resulting value is constant iff both inputs are.
Instance details Defined in Data.Active Methods (<>) :: Active a -> Active a -> Active a Source # sconcat :: NonEmpty (Active a) -> Active a Source # stimes :: Integral b => b -> Active a -> Active a Source #
Wrapped (Active a) Source # |
Instance details Defined in Data.Active Associated Types type Unwrapped (Active a) Source # Methods _Wrapped' :: Iso' (Active a) (Unwrapped (Active a)) Source #
Active a1 ~ t => Rewrapped (Active a2) t Source # |
Instance details Defined in Data.Active
type Unwrapped (Active a) Source # |
Instance details Defined in Data.Active type Unwrapped (Active a) = MaybeApply Dynamic a

mkActive :: Time Rational -> Time Rational -> (Time Rational -> a) -> Active a Source #

Create a dynamic `Active` from a start time, an end time, and a time-varying value.

fromDynamic :: Dynamic a -> Active a Source #

Create an `Active` value from a `Dynamic`.

isConstant :: Active a -> Bool Source #

Test whether an `Active` value is constant.

isDynamic :: Active a -> Bool Source #

Test whether an `Active` value is `Dynamic`.

onActive :: (a -> b) -> (Dynamic a -> b) -> Active a -> b Source #

Fold for `Active`s. Process an 'Active a', given a function to apply if it is a pure (constant) value, and a function to apply if it is a `Dynamic`.

modActive :: (a -> b) -> (Dynamic a -> Dynamic b) -> Active a -> Active b Source #

Modify an `Active` value using a case analysis to see whether it is constant or dynamic.

runActive :: Active a -> Time Rational -> a Source #

Interpret an `Active` value as a function from time.

activeEra :: Active a -> Maybe (Era Rational) Source #

Get the `Era` of an `Active` value (or `Nothing` if it is a constant/pure value).

setEra :: Era Rational -> Active a -> Active a Source #

Set the era of an `Active` value. Note that this will change a constant `Active` into a dynamic one which happens to have the same value at all times.

atTime :: Time Rational -> Active a -> Active a Source #

`atTime t a` is an active value with the same behavior as `a`, shifted so that it starts at time `t`. If `a` is constant it is returned unchanged.

activeStart :: Active a -> a Source #

Get the value of an `Active a` at the beginning of its era.

activeEnd :: Active a -> a Source #

Get the value of an `Active a` at the end of its era.

# Combinators

## Special active values

ui :: Fractional a => Active a Source #

`ui` represents the unit interval, which takes on the value `t` at time `t`, and has as its era `[0,1]`. It is equivalent to ``interval` 0 1`, and can be visualized as follows:

On the x-axis is time, and the value that `ui` takes on is on the y-axis. The shaded portion represents the era. Note that the value of `ui` (as with any active) is still defined outside its era, and this can make a difference when it is combined with other active values with different eras. Applying a function with `fmap` affects all values, both inside and outside the era. To manipulate values outside the era specifically, see `clamp` and `trim`.

To alter the values that `ui` takes on without altering its era, use its `Functor` and `Applicative` instances. For example, `(*2) <$> ui` varies from `0` to `2` over the era `[0,1]`. To alter the era, you can use `stretch` or `shift`.

interval :: Fractional a => Time Rational -> Time Rational -> Active a Source #

`interval a b` is an active value starting at time `a`, ending at time `b`, and taking the value `t` at time `t`.

## Transforming active values

stretch :: Rational -> Active a -> Active a Source #

`stretch s act` "stretches" the active `act` so that it takes `s` times as long (retaining the same start time).

stretchTo :: Duration Rational -> Active a -> Active a Source #

`stretchTo d` `stretch`es an `Active` so it has duration `d`. Has no effect if (1) `d` is non-positive, or (2) the `Active` value is constant, or (3) the `Active` value has zero duration. [AJG: conditions (1) and (3) no longer true: to consider changing]

during :: Active a -> Active a -> Active a Source #

`a1 `during` a2` `stretch`es and `shift`s `a1` so that it has the same era as `a2`. Has no effect if either of `a1` or `a2` are constant.

shift :: Duration Rational -> Active a -> Active a Source #

`shift d act` shifts the start time of `act` by duration `d`. Has no effect on constant values.

backwards :: Active a -> Active a Source #

Reverse an active value so the start of its era gets mapped to the end and vice versa. For example, `backwards `ui`` can be visualized as

snapshot :: Time Rational -> Active a -> Active a Source #

Take a "snapshot" of an active value at a particular time, resulting in a constant value.

## Working with values outside the era

clamp :: Active a -> Active a Source #

"Clamp" an active value so that it is constant before and after its era. Before the era, `clamp a` takes on the value of `a` at the start of the era. Likewise, after the era, `clamp a` takes on the value of `a` at the end of the era. `clamp` has no effect on constant values.

For example, `clamp `ui`` can be visualized as

See also `clampBefore` and `clampAfter`, which clamp only before or after the era, respectively.

clampBefore :: Active a -> Active a Source #

"Clamp" an active value so that it is constant before the start of its era. For example, `clampBefore `ui`` can be visualized as

See the documentation of `clamp` for more information.

clampAfter :: Active a -> Active a Source #

"Clamp" an active value so that it is constant after the end of its era. For example, `clampBefore `ui`` can be visualized as

See the documentation of `clamp` for more information.

trim :: Monoid a => Active a -> Active a Source #

"Trim" an active value so that it is empty outside its era. `trim` has no effect on constant values.

For example, `trim `ui`` can be visualized as

Actually, `trim ui` is not well-typed, since it is not guaranteed that `ui`'s values will be monoidal (and usually they won't be)! But the above image still provides a good intuitive idea of what `trim` is doing. To make this precise we could consider something like `trim (First . Just $ ui)`.

See also `trimBefore` and `trimActive`, which trim only before or after the era, respectively.

trimBefore :: Monoid a => Active a -> Active a Source #

"Trim" an active value so that it is empty before the start of its era. For example, `trimBefore `ui`` can be visualized as

See the documentation of `trim` for more details.

trimAfter :: Monoid a => Active a -> Active a Source #

"Trim" an active value so that it is empty after the end of its era. For example, `trimAfter `ui`` can be visualized as

See the documentation of `trim` for more details.

## Composing active values

after :: Active a -> Active a -> Active a Source #

`a1 `after` a2` produces an active that behaves like `a1` but is shifted to start at the end time of `a2`. If either `a1` or `a2` are constant, `a1` is returned unchanged.

(->>) :: Semigroup a => Active a -> Active a -> Active a infixr 5 Source #

Sequence/overlay two `Active` values: shift the second to start immediately after the first (using `after`), then compose them (using `<>`).

(|>>) :: Active a -> Active a -> Active a Source #

"Splice" two `Active` values together: shift the second to start immediately after the first (using `after`), and produce the value which acts like the first up to the common end/start point, then like the second after that. If both are constant, return the first.

movie :: [Active a] -> Active a Source #

Splice together a list of active values using `|>>`. The list must be nonempty.

# Discretization

discrete :: [a] -> Active a Source #

Create an `Active` which takes on each value in the given list in turn during the time `[0,1]`, with each value getting an equal amount of time. In other words, `discrete` creates a "slide show" that starts at time 0 and ends at time 1. The first element is used prior to time 0, and the last element is used after time 1.

It is an error to call `discrete` on the empty list.

simulate :: Rational -> Active a -> [a] Source #

`simulate r act` simulates the `Active` value `act`, returning a list of "snapshots" taken at regular intervals from the start time to the end time. The interval used is determined by the rate `r`, which denotes the "frame rate", that is, the number of snapshots per unit time.

If the `Active` value is constant (and thus has no start or end times), a list of length 1 is returned, containing the constant value.