-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Abstractions for animation -- -- Active abstraction for animated things with finite start and -- end times. @package active @version 0.2.0.8 -- | 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://ittc.ku.edu/csdl/fpg/node/46), 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 -- (http://projects.haskell.org/diagrams), 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.
module Data.Active
-- | An abstract type for representing points in time. Note that
-- literal numeric values may be used as Times, thanks to the
-- the Num and Fractional instances.
data Time n
-- | A convenient wrapper function to convert a numeric value into a time.
toTime :: n -> Time n
-- | A convenient unwrapper function to turn a time into a numeric value.
fromTime :: Time n -> n
-- | An abstract type representing elapsed time between two points
-- in time. Note that durations can be negative. Literal numeric values
-- may be used as Durations thanks to the Num and
-- Fractional instances.
data Duration n
-- | A convenient wrapper function to convert a numeric value into a
-- duration.
toDuration :: n -> Duration n
-- | A convenient unwrapper function to turn a duration into a numeric
-- value.
fromDuration :: Duration n -> n
-- | An Era is a concrete span of time, that is, a pair of times
-- representing the start and end of the era. Eras form a
-- semigroup: the combination of two Eras 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.
data Era n
-- | Create an Era by specifying start and end Times.
mkEra :: Time n -> Time n -> Era n
-- | Get the start Time of an Era.
start :: Era n -> Time n
-- | Get the end Time of an Era.
end :: Era n -> Time n
-- | Compute the Duration of an Era.
duration :: Num n => Era n -> Duration n
-- | 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.
data Dynamic a
Dynamic :: Era Rational -> (Time Rational -> a) -> Dynamic a
[era] :: Dynamic a -> Era Rational
[runDynamic] :: Dynamic a -> Time Rational -> a
-- | Create a Dynamic from a start time, an end time, and a
-- time-varying value.
mkDynamic :: Time Rational -> Time Rational -> (Time Rational -> a) -> Dynamic a
-- | Fold for Dynamic.
onDynamic :: (Time Rational -> Time Rational -> (Time Rational -> a) -> b) -> Dynamic a -> b
-- | Shift a Dynamic value by a certain duration.
shiftDynamic :: Duration Rational -> Dynamic a -> Dynamic a
-- | There are two types of Active values:
--
--
--
-- The addition of constant values enable Monoid and
-- Applicative instances for Active.
data Active a
-- | Create a dynamic Active from a start time, an end time, and a
-- time-varying value.
mkActive :: Time Rational -> Time Rational -> (Time Rational -> a) -> Active a
-- | Create an Active value from a Dynamic.
fromDynamic :: Dynamic a -> Active a
-- | Test whether an Active value is constant.
isConstant :: Active a -> Bool
-- | Test whether an Active value is Dynamic.
isDynamic :: Active a -> Bool
-- | Fold for Actives. 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.
onActive :: (a -> b) -> (Dynamic a -> b) -> Active a -> b
-- | Modify an Active value using a case analysis to see whether it
-- is constant or dynamic.
modActive :: (a -> b) -> (Dynamic a -> Dynamic b) -> Active a -> Active b
-- | Interpret an Active value as a function from time.
runActive :: Active a -> Time Rational -> a
-- | Get the Era of an Active value (or Nothing if it
-- is a constant/pure value).
activeEra :: Active a -> Maybe (Era Rational)
-- | 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.
setEra :: Era Rational -> Active a -> Active a
-- | 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.
atTime :: Time Rational -> Active a -> Active a
-- | Get the value of an Active a at the beginning of its era.
activeStart :: Active a -> a
-- | Get the value of an Active a at the end of its era.
activeEnd :: Active a -> a
-- | 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.
ui :: Fractional a => Active a
-- | interval a b is an active value starting at time a,
-- ending at time b, and taking the value t at time
-- t.
interval :: Fractional a => Time Rational -> Time Rational -> Active a
-- | stretch s act "stretches" the active act so that it
-- takes s times as long (retaining the same start time).
stretch :: Rational -> Active a -> Active a
-- | stretchTo d stretches 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]
stretchTo :: Duration Rational -> Active a -> Active a
-- | a1 `during` a2 stretches and shifts a1
-- so that it has the same era as a2. Has no effect if either of
-- a1 or a2 are constant.
during :: Active a -> Active a -> Active a
-- | shift d act shifts the start time of act by duration
-- d. Has no effect on constant values.
shift :: Duration Rational -> Active a -> Active a
-- | 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
--
backwards :: Active a -> Active a
-- | Take a "snapshot" of an active value at a particular time, resulting
-- in a constant value.
snapshot :: Time Rational -> Active a -> Active a
-- | "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.
clamp :: Active a -> Active a
-- | "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.
clampBefore :: Active a -> Active a
-- | "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.
clampAfter :: Active a -> Active a
-- | "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.
trim :: Monoid a => Active a -> Active a
-- | "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.
trimBefore :: Monoid a => Active a -> Active a
-- | "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.
trimAfter :: Monoid a => Active a -> Active a
-- | 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.
after :: Active a -> Active a -> Active a
-- | Sequence/overlay two Active values: shift the second to start
-- immediately after the first (using after), then compose them
-- (using <>).
(->>) :: Semigroup a => Active a -> Active a -> Active a
-- | "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.
(|>>) :: Active a -> Active a -> Active a
-- | Splice together a list of active values using |>>. The
-- list must be nonempty.
movie :: [Active a] -> Active a
-- | 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.
discrete :: [a] -> Active a
-- | 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.
simulate :: Rational -> Active a -> [a]
instance (Data.Functor.Bind.Class.MaybeApply f1 a1 ~ t0) => Control.Lens.Wrapped.Rewrapped (Data.Functor.Bind.Class.MaybeApply f0 a0) t0
instance Control.Lens.Wrapped.Wrapped (Data.Functor.Bind.Class.MaybeApply f0 a0)
instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Data.Active.Active a)
instance (GHC.Base.Monoid a, Data.Semigroup.Semigroup a) => GHC.Base.Monoid (Data.Active.Active a)
instance (Data.Active.Active a1 ~ t0) => Control.Lens.Wrapped.Rewrapped (Data.Active.Active a0) t0
instance Control.Lens.Wrapped.Wrapped (Data.Active.Active a0)
instance GHC.Base.Applicative Data.Active.Active
instance Data.Functor.Bind.Class.Apply Data.Active.Active
instance GHC.Base.Functor Data.Active.Active
instance GHC.Base.Functor Data.Active.Dynamic
instance GHC.Classes.Ord n => Data.Semigroup.Semigroup (Data.Active.Era n)
instance GHC.Show.Show n => GHC.Show.Show (Data.Active.Era n)
instance (Data.Active.Duration n1 ~ t0) => Control.Lens.Wrapped.Rewrapped (Data.Active.Duration n0) t0
instance Control.Lens.Wrapped.Wrapped (Data.Active.Duration n0)
instance GHC.Base.Applicative Data.Active.Duration
instance Linear.Vector.Additive Data.Active.Duration
instance GHC.Num.Num n => Data.Semigroup.Semigroup (Data.Active.Duration n)
instance GHC.Num.Num n => GHC.Base.Monoid (Data.Active.Duration n)
instance Data.Functor.Bind.Class.Apply Data.Active.Dynamic
instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Data.Active.Dynamic a)
instance GHC.Base.Functor Data.Active.Duration
instance GHC.Real.RealFrac n => GHC.Real.RealFrac (Data.Active.Duration n)
instance GHC.Real.Real n => GHC.Real.Real (Data.Active.Duration n)
instance GHC.Real.Fractional n => GHC.Real.Fractional (Data.Active.Duration n)
instance GHC.Num.Num n => GHC.Num.Num (Data.Active.Duration n)
instance GHC.Enum.Enum n => GHC.Enum.Enum (Data.Active.Duration n)
instance GHC.Read.Read n => GHC.Read.Read (Data.Active.Duration n)
instance GHC.Show.Show n => GHC.Show.Show (Data.Active.Duration n)
instance GHC.Classes.Ord n => GHC.Classes.Ord (Data.Active.Duration n)
instance GHC.Classes.Eq n => GHC.Classes.Eq (Data.Active.Duration n)
instance (Data.Active.Time n1 ~ t0) => Control.Lens.Wrapped.Rewrapped (Data.Active.Time n0) t0
instance Control.Lens.Wrapped.Wrapped (Data.Active.Time n0)
instance Linear.Affine.Affine Data.Active.Time
instance GHC.Base.Functor Data.Active.Time
instance GHC.Real.RealFrac n => GHC.Real.RealFrac (Data.Active.Time n)
instance GHC.Real.Real n => GHC.Real.Real (Data.Active.Time n)
instance GHC.Real.Fractional n => GHC.Real.Fractional (Data.Active.Time n)
instance GHC.Num.Num n => GHC.Num.Num (Data.Active.Time n)
instance GHC.Enum.Enum n => GHC.Enum.Enum (Data.Active.Time n)
instance GHC.Read.Read n => GHC.Read.Read (Data.Active.Time n)
instance GHC.Show.Show n => GHC.Show.Show (Data.Active.Time n)
instance GHC.Classes.Ord n => GHC.Classes.Ord (Data.Active.Time n)
instance GHC.Classes.Eq n => GHC.Classes.Eq (Data.Active.Time n)