@hackage varying0.1.3.0

Automaton based varying values, event streams and tweening.

varying

Hackage Build Status

This library provides automaton based varying values useful for both functional reactive programming (FRP) and locally stateful programming (LSP). It is influenced by the netwire and auto packages. Unlike netwire the concepts of inhibition and time are explicit (through Control.Varying.Event and Control.Varying.Time) and the library aims at being minimal and well documented with a small API.

Depending on your types and values varying can provide discrete or continuous time semantics.

Getting started

module Main where

import Control.Varying
import Control.Varying.Time as Time -- time is not auto-exported
import Text.Printf

-- | A simple 2d point type.
data Point = Point { x :: Float
                   , y :: Float
                   } deriving (Show, Eq)

-- | Our Point value that varies over time continuously in x and y.
backAndForth :: Var IO a Point
backAndForth =
    -- Here we use Applicative to construct a varying Point that takes time
    -- as an input.
    (Point <$> tweenx <*> tweeny)
        -- Here we feed the varying Point a time signal using the 'plug left'
        -- function. We could similarly use the 'plug right' (~>) function
        -- and put the time signal before the Point. This is needed because the
        -- tweens take time as an input.
        <~ time

-- An exponential tween back and forth from 0 to 100 over 2 seconds.
tweenx :: Monad m => Var m Float Float
tweenx =
    -- Tweens only happen for a certain duration and so their sample
    -- values have the type (Ord t, Fractional t => Event t). After construction
    -- a tween's full type will be
    -- (Ord t, Fractional t, Monad m) => Var m t (Event t).
     tween easeOutExpo 0 100 1
         -- We can chain another tween back to the starting position using
         -- `andThenE`, which will sample the first tween until it ends and then
         -- switch to sampling the next tween.
         `andThenE`
             -- Tween back to the starting position.
             tween easeOutExpo 100 0 1
                 -- At this point our resulting sample values will still have the
                 -- type (Event Float). The tween as a whole will be an event
                 -- stream. The tween also only runs back and forth once. We'd
                 -- like the tween to loop forever so that our point cycles back
                 -- and forth between 0 and 100 indefinitely.
                 -- We can accomplish this with recursion and the `andThen`
                 -- combinator, which samples an event stream until it
                 -- inhibits and then switches to a normal value stream (a
                 -- varying value). Put succinctly, it disolves our events into
                 -- values.
                 `andThen` tweenx

-- A quadratic tween back and forth from 0 to 100 over 2 seconds.
tweeny :: Monad m => Var m Float Float
tweeny =
    tween easeOutQuad 0 100 1 `andThenE` tween easeOutQuad 100 0 1 `andThen` tweeny

-- Our time signal.
time :: Var IO a Float
time = deltaUTC

main :: IO ()
main = do
    putStrLn "Varying Values"
    loop backAndForth
        where loop :: Var IO () Point -> IO ()
              loop v = do (point, vNext) <- runVar v ()
                          printf "\nPoint %03.1f %03.1f" (x point) (y point)
                          loop vNext