packages feed

varying 0.1.5.0 → 0.2.0.0

raw patch · 10 files changed

+310/−525 lines, 10 files

Files

README.md view
@@ -2,84 +2,76 @@ [![Hackage](https://img.shields.io/hackage/v/varying.svg)](http://hackage.haskell.org/package/varying) [![Build Status](https://travis-ci.org/schell/varying.svg)](https://travis-ci.org/schell/varying) -This library provides automaton based varying values useful for both functional+This library provides automaton based value streams useful for both functional reactive programming (FRP) and locally stateful programming (LSP). It is  influenced by the [netwire](http://hackage.haskell.org/package/netwire) and  [auto](http://hackage.haskell.org/package/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 +and `Control.Varying.Time`). 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  ```haskell module Main where  import Control.Varying-import Control.Varying.Time as Time -- time is not auto-exported+import Control.Applicative import Text.Printf  -- | A simple 2d point type.-data Point = Point { x :: Float-                   , y :: Float+data Point = Point { px :: Float+                   , py :: 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+-- An exponential tween back and forth from 0 to 100 over 2 seconds that+-- loops forever. This spline takes float values of delta time as input,+-- outputs the current x value at every step and would result in () if it+-- terminated.+tweenx :: (Applicative m, Monad m) => Spline Float Float m ()+tweenx = do+    -- Tween from 0 to 100 over 1 second+    x <- tween easeOutExpo 0 100 1+    -- Chain another tween back to the starting position+    _ <- tween easeOutExpo x 0 1+    -- Loop forever+    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+-- A quadratic tween back and forth from 0 to 100 over 2 seconds that never+-- ends.+tweeny :: (Applicative m, Monad m) => Spline Float Float m ()+tweeny = do+    y <- tween easeOutQuad 0 100 1+    _ <- tween easeOutQuad y 0 1+    tweeny --- Our time signal.+-- Our time signal that provides delta time samples. time :: Var IO a Float time = deltaUTC +-- | Our Point value that varies over time continuously in x and y.+backAndForth :: Var IO a Point+backAndForth =+    -- Turn our splines back into continuous value streams. We must provide+    -- a starting value since splines are not guaranteed to be defined at+    -- their edges.+    let x = execSpline 0 tweenx+        y = execSpline 0 tweeny+    in+    -- Construct a varying Point that takes time as an input.+    (Point <$> x <*> y)+        -- Stream in a time signal using the 'plug left' combinator.+        -- We could similarly use the 'plug right' (~>) function+        -- and put the time signal before the construction above. This is needed+        -- because the tween streams take time as an input.+        <~ time+ main :: IO () main = do-    putStrLn "Varying Values"+    putStrLn "Varying Example"     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)+                          printf "\nPoint %03.1f %03.1f" (px point) (py point)                           loop vNext ```
changelog.md view
@@ -2,3 +2,4 @@ ==========  0.1.5.0 - added Control.Varying.Spline+0.2.0.0 - reordered spline type variables for MonadTrans
src/Control/Varying.hs view
@@ -4,38 +4,34 @@ --  License:    MIT --  Maintainer: Schell Scivally <schell.scivally@synapsegroup.com> -----  The simplest, squishiest FRP library around.--- --  [@Core@]---  Get started writing varying values (also called streams) using the pure---  constructor 'var', the monadic constructor 'varM' or the raw constructor---  'Var'+--  Get started writing value streams using the pure constructor 'var', the+--  monadic constructor 'varM' or the raw constructor 'Var' -- --  [@Event@] --  Write event streams using the many event emitters and combinators. --+--  [@Spline@]+--  Use do-notation to sequence event streams to form complex behavior.+-- --  [@Tween@] --  Tween numerical values over time using interpolation functions and the --  "quick 'n dirty" time generators in 'Control.Varying.Time'. -- --  [@Time@]---  The 'Control.Varying.Time' module is not reexported because some of the---  functions collide with those in 'Event' - namely 'before' and 'after'.---  I think this is okay because in my experience most modules will either---  deal with events based on user input or events based on time, an in---  rare cases both - but in that case the majority of streams will be of one---  type making the choice of which module to import qualified an easy one.---  The time generator 'Control.Varying.Time.deltaUTC' in 'Control.Varying.Time'---  is practical and based on 'Data.Time.Clock.getCurrentTime'. It's meant---  to be simple, not optimal.+--  Create time streams and temporal event streams. -- module Control.Varying (     -- * Reexports     module Control.Varying.Core,     module Control.Varying.Event,-    module Control.Varying.Tween+    module Control.Varying.Spline,+    module Control.Varying.Time,+    module Control.Varying.Tween, ) where  import Control.Varying.Core import Control.Varying.Event import Control.Varying.Tween+import Control.Varying.Time+import Control.Varying.Spline
src/Control/Varying/Core.hs view
@@ -4,28 +4,28 @@ --   License:    MIT --   Maintainer: Schell Scivally <schell.scivally@synapsegroup.com> -----   Values that change over a given domain.+--   Value streams represent values that change over a given domain. -----   Varying values take some input (the domain ~ time, place, etc) and produce---   a sample and a new varying value. This pattern is known as an automaton.---   `varying` uses this pattern as its base type with the additon of a monadic---   computation to create locally stateful signals that change over some---   domain.+--   A stream takes some input (the domain e.g. time, place, etc) and when+--   sampled using 'runVar' - produces a value and a new value stream. This+--   pattern is known as an automaton. `varying` uses this pattern as its base+--   type with the additon of a monadic computation to create locally stateful+--   signals that change over some domain. module Control.Varying.Core (     Var(..),-    -- * Creating varying values+    -- * Creating value streams     -- $creation     var,     varM,     mkState,-    -- * Composing varying values+    -- * Composing value streams     -- $composition     (<~),     (~>),     -- * Adjusting and accumulating     delay,     accumulate,-    -- * Sampling varying values (running, entry points)+    -- * Sampling value streams (running and other entry points)     -- $running     evalVar,     execVar,@@ -33,7 +33,7 @@     loopVar_,     whileVar,     whileVar_,-    -- * Testing varying values+    -- * Testing value streams     testVar,     testVar_,     testWhile_,@@ -51,7 +51,7 @@ import Debug.Trace -------------------------------------------------------------------------------- -- $creation--- You can create a pure varying value by lifting a function @(a -> b)@+-- You can create a pure value stream by lifting a function @(a -> b)@ -- with 'var': -- -- @@@ -59,9 +59,9 @@ -- addsOne = var (+1) -- @ ----- 'var' is also equivalent to 'arr'.+-- 'var' is equivalent to 'arr'. ----- You can create a monadic varying value by lifting a monadic computation+-- You can create a monadic value stream by lifting a monadic computation -- @(a -> m b)@ using 'varM': -- -- @@@ -71,7 +71,7 @@ -- -- You can create either with the raw constructor. You can also create your -- own combinators using the raw constructor, as it allows you full control--- over how varying values are stepped and sampled:+-- over how value streams are stepped and sampled: -- -- @ -- delay :: Monad m => b -> Var m a b -> Var m a b@@ -101,17 +101,15 @@   return (b', mkState f s') -------------------------------------------------------------------------------- -- $running--- The easiest way to sample a 'Var' is to run it in the desired monad with--- 'runVar'. This will give you a sample value and a new 'Var' bundled up in a--- tuple:+-- The easiest way to sample a stream is to run it in the desired monad with+-- 'runVar'. This will produce a sample value and a new stream. -- -- > do (sample, v') <- runVar v inputValue -- -- Much like Control.Monad.State there are other entry points for running--- varying values like 'evalVar', 'execVar'. There are also extra control--- structures like 'loopVar' and 'whileVar' and more.+-- value streams like 'evalVar', 'execVar'. There are also extra control+-- structures such as 'loopVar' and 'whileVar'. --------------------------------------------------------------------------------- -- | Iterate a 'Var' once and return the sample value. evalVar :: Functor m => Var m a b -> a -> m b evalVar v a = fst <$> runVar v a@@ -193,8 +191,8 @@     let b' = f b a     return (b', accumulate f b') --- | Delays the given 'Var' by one sample using a parameter as the first--- sample. This enables the programmer to create 'Var's that depend on+-- | Delays the given stream by one sample using the argument as the first+-- sample. This enables the programmer to create streams that depend on -- themselves for values. For example: -- -- > let v = 1 + delay 0 v in testVar_ v@@ -204,11 +202,11 @@                                     return (b', go a' v'') -------------------------------------------------------------------------------- -- $composition--- You can compose varying values together using '~>' and '<~'. The "right plug"--- ('~>') takes the output from a varying value on the left and "plugs" it--- into the input of the varying value on the right. The "left plug" does--- the same thing only in the opposite direction. This allows you to write--- varying values that read naturally.+-- You can compose value streams together using '~>' and '<~'. The "right plug"+-- ('~>') takes the output from a value stream on the left and "plugs" it+-- into the input of the value stream on the right. The "left plug" does+-- the same thing in the opposite direction. This allows you to write value+-- streams that read naturally. -------------------------------------------------------------------------------- -- | Same as '~>' with flipped parameters. (<~) :: Monad m => Var m b c -> Var m a b -> Var m a c@@ -316,7 +314,7 @@ -------------------------------------------------------------------------------- -- Core datatypes ----------------------------------------------------------------------------------- | The vessel of a varying value. A 'Var' is a structure that contains a value+-- | The vessel of a value stream. A 'Var' is a structure that contains a value -- that changes over some input. That input could be time (Float, Double, etc) -- or 'Control.Varying.Event.Event's or 'Char' - whatever. -- It's a kind of Mealy machine (an automaton) with effects.
src/Control/Varying/Event.hs view
@@ -4,61 +4,42 @@ --   License:    MIT --   Maintainer: Schell Scivally <schell.scivally@synapsegroup.com> -----  'Event' streams describe things that happen at a specific time or place---  or value in general. For example, you can think of the event stream---  @Var IO Double (Event ())@ as an occurrence of `()` at a specific time---  (`Double`).------  You can use 'Event' just like you would 'Maybe'.+--  'Event' streams describe things that happen at a specific domain.+--  For example, you can think of the event stream+--  @Var IO Double (Event ())@ as an occurrence of () at a specific input+--  of type 'Double'. --+--  For sequencing streams please check out 'Control.Varying.Spline' which+--  lets you chain together sequences of event streams using do-notation. module Control.Varying.Event (     Event(..),     -- * Transforming event values.     toMaybe,     isEvent,-    -- * Combining event streams and value streams-    latchWith,+    -- * Combining event and value streams     orE,-    tagOn,-    tagM,-    --ringM,-    -- * Generating events from values+    -- * Generating events from value streams     use,     onTrue,     onJust,     onUnique,     onWhen,-    toEvent,-    -- * Using event streams+    -- * Folding and gathering event streams     foldStream,-    collect,-    collectWith,-    hold,-    holdWith,-    startingWith,-    startWith,-    -- * Temporal operations (time - related)-    between,-    after,-    beforeWith,-    beforeOne,-    before,+    startingWith, startWith,+    -- * List-like operations on event streams     filterE,     takeE,     dropE,+    -- * Primitive event streams     once,     always,     never,-    -- * Switching and chaining events-    andThen,-    andThenWith,-    andThenE,+    -- * Switching     switchByMode,+    -- * Bubbling     onlyWhen,     onlyWhenE,-    -- * Combining event streams-    combineWith,-    combine ) where  import Prelude hiding (until)@@ -67,7 +48,7 @@ import Control.Monad import Data.Monoid ----------------------------------------------------------------------------------- Transforming event values into usable values.+-- Transforming event values into usable values -------------------------------------------------------------------------------- -- | Turns an 'Event' into a 'Maybe'. toMaybe :: Event a -> Maybe a@@ -80,24 +61,8 @@ isEvent (Event _) = True isEvent _ = False ----------------------------------------------------------------------------------- Combining varying values and events+-- Combining value streams and events ----------------------------------------------------------------------------------- | Holds the last value of one event stream while waiting for another event--- stream to produce a value. Once both streams have produced a value, combine--- the two using the given combine function and emit an event with the--- value.-latchWith :: (Applicative m, Monad m)-          => (b -> c -> d) -> Var m a (Event b) -> Var m a (Event c)-          -> Var m a (Event d)-latchWith f vb = latchWith' (NoEvent, vb)-    where latchWith' (eb, vb') vc =-              Var $ \a -> do (eb', vb'') <- runVar vb' a-                             (ec', vc') <- runVar vc a-                             let eb'' = eb' <|> eb-                             return ( f <$> eb'' <*> ec'-                                    , latchWith' (eb'', vb'') vc'-                                    )- -- | Produces values from the first unless the second produces event -- values and if so, produces the values of those events. orE :: (Applicative m, Monad m) => Var m a b -> Var m a (Event b) -> Var m a b@@ -107,37 +72,6 @@     return $ case e of         NoEvent  -> (b, orE y' ye')         Event b' -> (b', orE y' ye')---- | Injects the values of the `vb` into the events of `ve`.-tagOn :: (Applicative m, Monad m)-      => Var m a b -> Var m a (Event c) -> Var m a (Event b)-tagOn vb ve = (<$) <$> vb <*> ve---- | Injects a monadic computation into an event stream, using the event--- values of type `b` as a parameter to produce an event stream of type--- `c`. After the first time an event is generated the result of the--- previous event is used in a clean up function.------ This is like `tagM` but performs a cleanup function first.---ringM :: (Applicative m, Monad m)---      => (c -> m ()) -> (b -> m c) -> Var m a (Event b) -> Var m a (Event c)---ringM cln = (go (const $ return ()) .) . tagM---    where go f ve = Var $ \a -> do (ec, ve') <- runVar ve a---                                   case ec of---                                       NoEvent -> return (ec, go f ve')---                                       Event c -> do f c---                                                     return (ec, go cln ve')---- | Injects a monadic computation into the events of `vb`, providing a way--- to perform side-effects inside an `Event` inside a `Var`.-tagM :: (Applicative m, Monad m)-     => (b -> m c) -> Var m a (Event b) -> Var m a (Event c)-tagM f vb = Var $ \a -> do-    (eb, vb') <- runVar vb a-    case eb of-        Event b -> do c <- f b-                      return (Event c, tagM f vb')-        NoEvent -> return (NoEvent, tagM f vb') -------------------------------------------------------------------------------- -- Generating events from values --------------------------------------------------------------------------------@@ -171,23 +105,9 @@ -- | Triggers an `Event a` when the condition is met. onWhen :: Applicative m => (a -> Bool) -> Var m a (Event a) onWhen f = var $ \a -> if f a then Event a else NoEvent---- | Wraps all produced values of the given var with events.-toEvent :: (Applicative m, Monad m) => Var m a b -> Var m a (Event b)-toEvent = (~> var Event) ----------------------------------------------------------------------------------- Using event values+-- Collecting ----------------------------------------------------------------------------------- | Collect all produced values into a monoidal structure using the given--- insert function.-collectWith :: (Monoid b, Applicative m, Monad m)-            => (a -> b -> b) -> Var m (Event a) b-collectWith f = Var $ \a -> collect' mempty a-    where collect' b e = let b' = case e of-                                        NoEvent -> b-                                        Event a' -> f a' b-                          in return (b', Var $ \a' -> collect' b' a')- -- | Like a left fold over all the stream's produced values. foldStream :: Monad m => (a -> t -> a) -> a -> Var m (Event t) a foldStream f acc = Var $ \e ->@@ -196,95 +116,15 @@                    in return (acc', foldStream f acc')         NoEvent -> return (acc, foldStream f acc) --- | Collect all produced values into a list. The latest event value will--- be at the head of the list.-collect :: (Applicative m, Monad m) => Var m (Event a) [a]-collect = collectWith (:)- -- | Produces the given value until the input events produce a value, then -- produce that value until a new input event produces. This always holds -- the last produced value, starting with the given value. -- @ -- time ~> after 3 ~> startingWith 0 -- @--- This is similar to 'hold' except that it takes events from its input value--- instead of another 'Var'. startingWith, startWith :: (Applicative m, Monad m) => a -> Var m (Event a) a startingWith = startWith-startWith a = Var $ \e ->-    return $ case e of-                 NoEvent  -> (a, startWith a)-                 Event a' -> (a', startWith a')---- | Flipped version of 'hold'.-holdWith :: (Applicative m, Monad m) => b -> Var m a (Event b) -> Var m a b-holdWith = flip hold---- | Produces the 'initial' value until the given 'Var' produces an event.--- After an event is produced that event's value will be produced until the--- next event produced by the given 'Var'.-hold :: (Applicative m, Monad m) => Var m a (Event b) -> b -> Var m a b-hold w initial = Var $ \x -> do-    (mb, w') <- runVar w x-    return $ case mb of-        NoEvent -> (initial, hold w' initial)-        Event e -> (e, hold w' e)---- | Produce events after the first until the second. After a successful--- cycle it will start over.-between :: (Applicative m, Monad m)-        => Var m a (Event b) -> Var m a (Event c) -> Var m a (Event ())-between vb vc = (never `before` vb) `andThenE` (toEvent vu `before` vc) `andThen` between vb vc-    where vu = pure ()---- | Produce events with the initial value only after the input stream has--- produced one event.-after :: (Applicative m, Monad m)-      => Var m a b -> Var m a (Event c) -> Var m a (Event b)-after vb ve = Var $ \a -> do-    (_, vb') <- runVar vb a-    (e, ve') <- runVar ve a-    case e of-        Event _ -> return (NoEvent, toEvent vb')-        NoEvent -> return (NoEvent, vb' `after` ve')---- | Like before, but use the value produced by the switching stream to--- create a stream to switch to.-beforeWith :: (Applicative m, Monad m)-           => Var m a b-           -> (Var m a (Event b), b -> Var m a (Event b))-           -> Var m a (Event b)-beforeWith vb (ve, f) = Var $ \a -> do-    (b, vb') <- runVar vb a-    (e, ve') <- runVar ve a-    case e of-        Event b' -> runVar (f b') a-        NoEvent  -> return (Event b, beforeWith vb' (ve', f))---- | Like before, but sample the value of the second stream once before--- inhibiting.-beforeOne :: (Applicative m, Monad m) => Var m a b -> Var m a (Event b) -> Var m a (Event b)-beforeOne vb ve = Var $ \a -> do-    (b, vb') <- runVar vb a-    (e, ve') <- runVar ve a-    case e of-        Event b' -> return (Event b', never)-        NoEvent  -> return (Event b, vb' `beforeOne` ve')---- | Produce events of the initial varying value until the given event stream--- produces its first event, then inhibit forever.-before :: (Applicative m, Monad m)-       => Var m a b -> Var m a (Event c) -> Var m a (Event b)-before vb ve = Var $ \a -> do-    (b, vb') <- runVar vb a-    (e, ve') <- runVar ve a-    case e of-        Event _ -> return (NoEvent, never)-        NoEvent -> return (Event b, vb' `before` ve')---- | Produce the given value once and then inhibit forever.-once :: (Applicative m, Monad m) => b -> Var m a (Event b)-once b = Var $ \_ -> return (Event b, never)+startWith = foldStream (\_ a -> a)  -- | Stream through some number of successful events and then inhibit forever. takeE :: (Applicative m, Monad m)@@ -312,6 +152,12 @@ filterE p v = v ~> var check     where check (Event b) = if p b then Event b else NoEvent           check _ = NoEvent+--------------------------------------------------------------------------------+-- Primitive event streams+--------------------------------------------------------------------------------+-- | Produce the given value once and then inhibit forever.+once :: (Applicative m, Monad m) => b -> Var m a (Event b)+once b = Var $ \_ -> return (Event b, never)  -- | Never produces any event values. never :: (Applicative m, Monad m) => Var m b (Event c)@@ -321,36 +167,9 @@ always :: (Applicative m, Monad m) => b -> Var m a (Event b) always = pure . Event ----------------------------------------------------------------------------------- Switching on events+-- Switching ----------------------------------------------------------------------------------- | Produces the first 'Var's Event values until that stops producing, then--- switches to the second 'Var'.-andThen :: (Applicative m, Monad m) => Var m a (Event b) -> Var m a b -> Var m a b-andThen w1 w2 = w1 `andThenWith` const w2---- | Switches from one event stream to another once the first stops--- producing.-andThenE :: (Applicative m, Monad m)-         => Var m a (Event b) -> Var m a (Event b) -> Var m a (Event b)-andThenE y1 y2 = Var $ \a -> do-    (e, y1') <- runVar y1 a-    case e of-        NoEvent -> runVar y2 a-        Event b -> return (Event b, y1' `andThenE` y2)---- | Switches from one event stream when that stream stops producing. A new--- stream is created using the last produced value (or `Nothing`) and used--- as the second stream.-andThenWith :: (Applicative m, Monad m)-            => Var m a (Event b) -> (Maybe b -> Var m a b) -> Var m a b-andThenWith = go Nothing-    where go mb w1 f = Var $ \a -> do-              (e, w1') <- runVar w1 a-              case e of-                  NoEvent -> runVar (f mb) a-                  Event b -> return (b, go (Just b) w1' f)---- | Switches using a mode signal. Signals maintain state for the duration+-- | Switches using a mode signal. Streams maintain state only for the duration -- of the mode. switchByMode :: (Applicative m, Monad m, Eq b)              => Var m a b -> (b -> Var m a c) -> Var m a c@@ -365,22 +184,24 @@                       where vOf eb = case eb of                                          NoEvent -> v                                          Event b -> f b---- | Produce events of a varying value 'v' only when its input value passes a+--------------------------------------------------------------------------------+-- Bubbling+--------------------------------------------------------------------------------+-- | Produce events of a value stream 'v' only when its input value passes a -- predicate 'f'. -- 'v' maintains state while cold. onlyWhen :: (Applicative m, Monad m)-         => Var m a b -- ^ 'v' - The varying value+         => Var m a b -- ^ 'v' - The value stream          -> (a -> Bool) -- ^ 'f' - The predicate to run on 'v''s input values.          -> Var m a (Event b) onlyWhen v f = v `onlyWhenE` hot     where hot = var id ~> onWhen f --- | Produce events of a varying value 'v' only when an event stream 'h'+-- | Produce events of a value stream 'v' only when an event stream 'h' -- produces an event. -- 'v' and 'h' maintain state while cold. onlyWhenE :: (Applicative m, Monad m)-          => Var m a b -- ^ 'v' - The varying value+          => Var m a b -- ^ 'v' - The value stream           -> Var m a (Event c) -- ^ 'h' - The event stream           -> Var m a (Event b) onlyWhenE v hot = Var $ \a -> do@@ -390,22 +211,7 @@             return (Event b, onlyWhenE v' hot')     else return (NoEvent, onlyWhenE v hot') ----------------------------------------------------------------------------------- Combining event streams------------------------------------------------------------------------------------ | Combine two events streams into one event stream. Like `combine` but--- uses a combining function instead of (,).-combineWith :: (Applicative m, Monad m)-            => (b -> c -> d) -> Var m a (Event b) -> Var m a (Event c)-            -> Var m a (Event d)-combineWith f vb vc = (uncurry f <$>) <$> combine vb vc---- | Combine two event streams into an event stream of tuples. A tuple is--- only produced when both event streams produce a value.-combine :: (Applicative m, Monad m)-        => Var m a (Event b) -> Var m a (Event c) -> Var m a (Event (b,c))-combine vb vc = (\eb ec -> (,) <$> eb <*> ec) <$> vb <*> vc------------------------------------------------------------------------------------ Operations on Events+-- Event typeclass instances -------------------------------------------------------------------------------- instance Show a => Show (Event a) where     show (Event a) = "Event " ++ show a@@ -431,7 +237,9 @@     signum = fmap signum     fromInteger = pure . fromInteger -instance MonadPlus Event+instance MonadPlus Event where+    mzero = mempty+    mplus = (<|>)  instance Monad Event where    return = Event@@ -460,8 +268,7 @@     fmap f (Event a) = Event $ f a     fmap _ NoEvent = NoEvent --- | For all intents and purposes you can think of an Event as a Maybe.--- A value of @Event ()@ means that an event has occurred and that the+-- | A value of @Event ()@ means that an event has occurred and that the -- result is a @()@. A value of @NoEvent@ means that an event did not -- occur. --
src/Control/Varying/Spline.hs view
@@ -4,23 +4,24 @@ --   License:    MIT --   Maintainer: Schell Scivally <schell.scivally@synapsegroup.com> -----  Using splines we can easily create continuously varying values from+--  Using splines we can easily create continuous value streams from --  multiple piecewise event streams. A spline is a monadic layer on top of --  event streams which are only continuous over a certain domain. The idea --  is that we use do notation to "run an event stream" from which we will---  consume produced values. Once the event stream inhibits the do-notation---  computation completes and returns a result value. That result value is then---  used to determine the next spline in the sequence. This allows us to build---  up long, complex behaviors sequentially using a very familiar notation---  that can be easily turned into a continuously varying value.-+--  consume produced values. Once the event stream inhibits the computation+--  completes and returns a result value. That result value is then+--  used to determine the next spline in the sequence.+--+--  A spline can be converted back into a value stream using 'execSpline' or+--  'execSplineT'. This allows us to build long, complex, sequential behaviors+--  using familiar notation.+-- {-# LANGUAGE GADTs #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TupleSections #-} module Control.Varying.Spline (     -- * Spline     Spline,-    runSpline,     execSpline,     spline,     -- * Spline Transformer@@ -28,8 +29,12 @@     runSplineT,     evalSplineT,     execSplineT,-    varyUntilEvent,+    -- * Special operations.+    untilEvent,+    race,+    mix,     capture,+    mapOutput,     -- * Step     Step(..), ) where@@ -37,6 +42,8 @@ import Control.Varying.Core import Control.Varying.Event import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Control.Monad import Control.Applicative import Data.Monoid @@ -54,6 +61,10 @@ stepResult :: Step f b -> Event b stepResult (Step _ b) = b +toIter :: (Functor f, Monoid (f b))+         => (f a -> f b) -> Step (f a) c -> Step (f b) c+toIter f (Step a b) = Step (f a) b+ -- | A discrete step is a functor by applying a function to the contained -- event's value. instance Functor (Step f) where@@ -80,24 +91,24 @@ -- Much like the State monad it has an "internal state" and an eventual -- return value, where the internal state is the output value. The result -- value is used only in determining the next spline to sequence.-data SplineT m f a b c = SplineT { unSplineT :: Var m a (Step (f b) c) }+data SplineT f a b m c = SplineT { unSplineT :: Var m a (Step (f b) c) }                        | SplineTConst c --- | Unwrap a spline into a varying value.+-- | Unwrap a spline into a value stream. runSplineT :: (Applicative m, Monad m, Monoid (f b))-           => SplineT m f a b c -> Var m a (Step (f b) c)+           => SplineT f a b m c -> Var m a (Step (f b) c) runSplineT (SplineT v) = v runSplineT (SplineTConst x) = pure $ pure x  -- | 'Spline' is a specialized 'SplineT' that uses Event as its output -- container. This means that new values overwrite/replace old values due to -- Event's 'Last'-like monoid instance.-type Spline m a b c = SplineT m Event a b c+type Spline a b m c = SplineT Event a b m c  -- | A spline is a functor by applying the function to the result.-instance (Applicative m, Monad m) => Functor (SplineT m f a b) where-    fmap f (SplineT v) = SplineT $ fmap (fmap f) v+instance (Applicative m, Monad m) => Functor (SplineT f a b m) where     fmap f (SplineTConst c)  = SplineTConst $ f c+    fmap f (SplineT v) = SplineT $ fmap (fmap f) v  -- | A spline is an applicative if its output type is a monoid. It -- responds to 'pure' by returning a spline that immediately returns the@@ -105,7 +116,7 @@ -- value (the function) to the right arguments eventual value. The -- output values will me combined with 'mappend'. instance (Monoid (f b), Applicative m, Monad m)-    => Applicative (SplineT m f a b) where+    => Applicative (SplineT f a b m) where     pure = SplineTConst     (SplineTConst f) <*> (SplineTConst x) = SplineTConst $ f x     (SplineT vf) <*> (SplineTConst x) = SplineT $ fmap (fmap ($ x)) vf@@ -115,7 +126,8 @@ -- | A spline is monad if its output type is a monoid. A spline responds -- to bind by running until it produces an eventual value, then uses that -- value to run the next spline.-instance (Monoid (f b), Applicative m, Monad m) => Monad (SplineT m f a b) where+instance (Monoid (f b), Applicative m, Monad m) => Monad (SplineT f a b m) where+    return = pure     (SplineTConst x) >>= f = f x     (SplineT v) >>= f = SplineT $ Var $ \i -> do         (Step b e, v') <- runVar v i@@ -123,25 +135,28 @@             NoEvent -> return (Step b NoEvent, runSplineT $ SplineT v' >>= f)             Event x -> runVar (runSplineT $ f x) i +-- | A spline is a transformer and other monadic computations can be lifted+-- int a spline.+instance Monoid (f b) => MonadTrans (SplineT f a b) where+    lift f = SplineT $ varM $ const $ liftM (Step mempty . Event) f+ -- | A spline can do IO if its underlying monad has a MonadIO instance. It -- takes the result of the IO action as its immediate return value and -- uses 'mempty' to generate an empty output value. instance (Monoid (f b), Functor m, Applicative m, MonadIO m)-    => MonadIO (SplineT m f a b) where-    liftIO f = SplineT $ Var $ \_ -> do-        n <- (Step mempty . Event) <$> liftIO f-        return (n, pure n)+    => MonadIO (SplineT f a b m) where+    liftIO = lift . liftIO --- | Evaluates a spline to a varying value of its output type.+-- | Evaluates a spline to a value stream of its output type. execSplineT :: (Applicative m, Monad m, Monoid (f b))-            => SplineT m f a b c -> Var m a (f b)+            => SplineT f a b m c -> Var m a (f b) execSplineT = (stepIter <$>) . runSplineT  -- | Evaluates a spline to an event stream of its result. The resulting--- varying value inhibits until the spline's domain is complete and then it+-- value stream inhibits until the spline's domain is complete and then it -- produces events of the result type. evalSplineT :: (Applicative m, Monad m, Monoid (f b))-            => SplineT m f a b c -> Var m a (Event c)+            => SplineT f a b m c -> Var m a (Event c) evalSplineT = (stepResult <$>) . runSplineT  -- | Create a spline using an event stream. The spline will run until the@@ -149,47 +164,83 @@ -- output value. In the case the stream inhibits before producing -- a value the default value is used. The spline's result value is the last -- output value.-spline :: (Applicative m, Monad m) => b -> Var m a (Event b) -> Spline m a b b+spline :: (Applicative m, Monad m) => b -> Var m a (Event b) -> Spline a b m b spline x ve = SplineT $ Var $ \a -> do     (ex, ve') <- runVar ve a     case ex of         NoEvent  -> let n = Step (Event x) (Event x) in return (n, pure n)         Event x' -> return (Step (Event x') NoEvent, runSplineT $ spline x' ve') --- | Unwrap a spline into a varying value. This is an alias of--- 'runSplineT'.-runSpline :: (Applicative m, Monad m) => Spline m a b c -> Var m a (Step (Event b) c)-runSpline = runSplineT---- | Using a default start value, evaluate the spline to a varying value.+-- | Using a default start value, evaluate the spline to a value stream. -- A spline is only defined over a finite domain so we must supply a default -- value to use before the spline produces its first output value.-execSpline :: (Applicative m, Monad m) => b -> Spline m a b c -> Var m a b+execSpline :: (Applicative m, Monad m) => b -> Spline a b m c -> Var m a b execSpline x (SplineTConst _) = pure x execSpline x s = execSplineT s ~> foldStream (\_ y -> y) x --- | Create a spline from a varying value and an event stream. The spline--- uses the varying value as its output value. The spline will run until+-- | Create a spline from a value stream and an event stream. The spline+-- uses the value stream as its output value. The spline will run until -- the event stream produces a value, at that point the last output--- value and the event value are used in a merge function to produce the--- spline's result value.-varyUntilEvent :: (Applicative m, Monad m)-               => Var m a b -> Var m a (Event c) -> (b -> c -> d)-               -> Spline m a b d-varyUntilEvent v ve f = SplineT $ Var $ \a -> do-    (b, v') <- runVar v a-    (ec, ve') <- runVar ve a-    case ec of-        NoEvent -> return (Step (Event b) NoEvent,-                           runSplineT $ varyUntilEvent v' ve' f)-        Event c -> let n = Step (Event b) (Event $ f b c)-                   in return (n, pure n)+-- value and the event value are tupled and returned as the spline's result+-- value.+untilEvent :: (Applicative m, Monad m)+           => Var m a b -> Var m a (Event c)+           -> Spline a b m (b,c)+untilEvent v ve = SplineT $ t ~> var (uncurry f)+    where t = (,) <$> v <*> ve+          f b ec = case ec of+                       NoEvent -> Step (Event b) NoEvent+                       Event c -> Step (Event b) (Event (b, c)) +-- | Run two splines concurrently and return the result of the SplineT that+-- concludes first. If they conclude at the same time the result is taken from+-- the spline on the left.+race :: (Applicative m, Monad m, Monoid (f u))+          => SplineT f i u m a -> SplineT f i u m a -> SplineT f i u m a+race (SplineTConst a) s =+    race (SplineT $ pure $ Step mempty $ Event a) s+race s (SplineTConst b) =+    race s (SplineT $ pure $ Step mempty $ Event b)+race (SplineT va) (SplineT vb) = SplineT $ Var $ \i -> do+    (Step ua ea, va') <- runVar va i+    (Step ub eb, vb') <- runVar vb i+    case (ea,eb) of+        (Event _,_) -> return (Step (ua <> ub) ea, va')+        (_,Event _) -> return (Step (ua <> ub) eb, vb')+        (_,_)       -> return (Step (ua <> ub) NoEvent,+                               runSplineT $ race (SplineT va') (SplineT vb'))++-- | Run a list of splines concurrently. Restart individual splines whenever+-- they conclude in a value. Return a list of the most recent result values once+-- the control spline concludes.+mix :: (Applicative m, Monad m, Monoid (f b))+    => [Maybe c -> SplineT f a b m c] -> SplineT f a b m ()+    -> SplineT f a b m [Maybe c]+mix gs = go gs es $ zipWith ($) gs xs+    where es = replicate n NoEvent+          xs = replicate n Nothing+          n  = length gs+          go fs evs guis egui = SplineT $ Var $ \a -> do+            let step (ecs, fb, vs) (f, ec, g) = do+                    (Step fb' ec', v) <- runVar (runSplineT g) a+                    let ec'' = ec <> ec'+                        fb'' = fb <> fb'+                        v'   = case ec' of+                                   NoEvent -> v+                                   Event c -> runSplineT $ f $ Just c+                    return (ecs ++ [ec''], fb'', vs ++ [SplineT v'])+            (ecs, fb, guis') <- foldM step ([],mempty,[]) (zip3 fs evs guis)+            (Step fb' ec, v) <- runVar (runSplineT egui) a+            let fb'' = fb <> fb'+                ec' = map toMaybe ecs <$ ec+            return (Step fb'' ec',+                    runSplineT $ go fs ecs guis' $ SplineT v)+ -- | Capture the spline's latest output value and tuple it with the -- spline's result value. This is helpful when you want to sample the last -- output value in order to determine the next spline to sequence. capture :: (Applicative m, Monad m, Monoid (f b), Eq (f b))-        => SplineT m f a b c -> SplineT m f a b (f b, c)+        => SplineT f a b m c -> SplineT f a b m (f b, c) capture (SplineTConst x) = SplineTConst (mempty, x) capture (SplineT v) = capture' mempty v     where capture' mb v' = SplineT $ Var $ \a -> do@@ -197,3 +248,9 @@               let mb' = if fb == mempty then mb else fb                   ec' = (mb',) <$> ec               return (Step fb ec', runSplineT $ capture' mb' v'')++-- | Map the output value of a spline.+mapOutput :: (Functor f, Monoid (f t), Applicative m, Monad m)+          => Var m a (f b -> f t) -> SplineT f a b m c -> SplineT f a t m c+mapOutput _ (SplineTConst c) = SplineTConst c+mapOutput vf (SplineT vx) = SplineT $ toIter <$> vf <*> vx
src/Control/Varying/Time.hs view
@@ -6,15 +6,15 @@ module Control.Varying.Time where  import Control.Varying.Core-import Control.Varying.Event hiding (after, before)+import Control.Varying.Event import Control.Applicative import Data.Time.Clock --- | Produces "time" deltas using 'getCurrentTime' and 'diffUTCTime'.+-- | Produces time deltas using 'getCurrentTime' and 'diffUTCTime'. deltaUTC :: Fractional t => Var IO b t deltaUTC = delta getCurrentTime (\a b -> realToFrac $ diffUTCTime a b) --- | Produces "time" deltas using a monadic computation and a difference+-- | Produces time deltas using a monadic computation and a difference -- function. delta :: (Num t, Fractional t, Applicative m, Monad m)       => m a -> (a -> a -> t) -> Var m b t@@ -32,16 +32,16 @@ -- Note that as soon as we have accumulated >= t we stop emitting events -- and there is no guarantee that an event will be emitted at time == t. before :: (Applicative m, Monad m, Num t, Ord t) => t -> Var m t (Event ())-before t = Var $ \dt -> do+before t = Var $ \dt -> return $     if t - dt >= 0-    then return (Event (), before $ t - dt)-    else return (NoEvent, never)+    then (Event (), before $ t - dt)+    else (NoEvent, never)  -- | Emits events after t input has been accumulated. -- Note that event emission is not guaranteed to begin exactly at t, -- only at some small delta after t. after :: (Applicative m, Monad m, Num t, Ord t) => t -> Var m t (Event ())-after t = Var $ \dt -> do+after t = Var $ \dt -> return $     if t - dt <= 0-    then return (Event (), pure $ Event ())-    else return (NoEvent, after $ t - dt)+    then (Event (), pure $ Event ())+    else (NoEvent, after $ t - dt)
src/Control/Varying/Tween.hs view
@@ -22,39 +22,30 @@     -- $creation     tween,     constant,-    -- * Tweening with splines-    -- $splines-    tweenTo,     -- * Interpolation functions     -- $lerping     linear,     easeInCirc,     easeOutCirc,-    easeInOutCirc,     easeInExpo,     easeOutExpo,-    easeInOutExpo,     easeInSine,     easeOutSine,     easeInOutSine,     easeInPow,     easeOutPow,-    easeInOutPow,     easeInCubic,     easeOutCubic,-    easeInOutCubic,     easeInQuad,     easeOutQuad,-    easeInOutQuad,-    -- * Interpolation helpers-    easeInOut,     -- * Writing your own tweens+    -- $writing     Tween,     Easing ) where  import Control.Varying.Core-import Control.Varying.Event hiding (after, before)+import Control.Varying.Event import Control.Varying.Spline import Control.Varying.Time import Control.Arrow@@ -76,10 +67,6 @@ easeOutQuad :: Num t => Easing t easeOutQuad c t b =  (-c) * (t * (t - 2)) + b --- | Ease in and out quadratic.-easeInOutQuad :: (Ord t, Fractional t) => Easing t-easeInOutQuad = easeInOut easeInQuad easeOutQuad- -- | Ease in cubic. easeInCubic :: Num t => Easing t easeInCubic c t b =  c * t*t*t + b@@ -88,14 +75,6 @@ easeOutCubic :: Num t => Easing t easeOutCubic c t b =  let t' = t - 1 in c * (t'*t'*t' + 1) + b --- | Ease in and out cubic.-easeInOutCubic :: (Ord t, Fractional t) => Easing t-easeInOutCubic = easeInOut easeInCubic easeOutCubic---- | Ease in and out by some power.-easeInOutPow :: (Fractional t, Ord t) => Int -> Easing t-easeInOutPow p = easeInOut (easeInPow p) (easeOutPow p)- -- | Ease in by some power. easeInPow :: Num t => Int -> Easing t easeInPow power c t b =  c * (t^power) + b@@ -130,10 +109,6 @@ easeOutExpo :: Floating t => Easing t easeOutExpo c t b =  let e = -10 * t in c * (-(2**e) + 1) + b --- | Ease in and out exponential.-easeInOutExpo :: (Ord t, Floating t) => Easing t-easeInOutExpo = easeInOut easeInExpo easeOutExpo- -- | Ease in circular. easeInCirc :: Floating t => Easing t easeInCirc c t b = let s = sqrt (1 - t*t) in -c * (s - 1) + b@@ -144,96 +119,61 @@                         s  = sqrt (1 - t'*t')                     in c * s + b --- | Ease in and out circular.-easeInOutCirc :: (Ord t, Floating t) => Easing t-easeInOutCirc = easeInOut easeInCirc easeOutCirc---- | Ease in and out using the given easing equations.-easeInOut :: (Ord t, Num t, Fractional t) => Easing t -> Easing t -> Easing t-easeInOut ein eout c t b = if t >= 0.5 then ein c t b else eout c t b- -- | Ease linear. linear :: Num t => Easing t linear c t b = c * t + b  -------------------------------------------------------------------------------- -- $creation--- -- The most direct route toward tweening values is to use 'tween'--- along with an interpolation function such as 'easeInOutExpo'. For example,--- @tween easeInOutExpo 0 100 10@, this will create an event stream that--- produces @Event t@s where `t` is tweened from 0 to 100 over 10 seconds.--- Once the 10 seconds are up, the stream will inhibit (produce `NoEvent`)--- forever. To create a stream of `t` that is tweened from 0 to 100 and--- then stays at 100 forever after requires you to use a combinator from the--- 'Event' module, like so:------ >tween easeInOutExpo 0 100 10 `andThen` 100------ The 'andThen' combinator "disolves" our 'Event's by switching to--- another stream once the first inhibits.+-- along with an interpolation function such as 'easeInExpo'. For example,+-- @tween easeInOutExpo 0 100 10@, this will create a spline that produces a+-- number interpolated from 0 to 100 over 10 seconds. At the end of the+-- tween the spline will return the result value. -------------------------------------------------------------------------------- --- | Creates an event stream that produces an event value interpolated between--- a start and end value using an easing equation ('Easing') over a duration.--- The resulting 'Var' will take a time delta as input. For example:+-- | Creates a spline that produces a value interpolated between a start and+-- end value using an easing equation ('Easing') over a duration.  The+-- resulting spline will take a time delta as input. For example: -- -- @--- testWhile_ isEvent v+-- testWhile_ isEvent (deltaUTC ~> v) --    where v :: Var IO a (Event Double)---          v = deltaUTC ~> tween easeOutExpo 0 100 5+--          v = execSpline 0 $ tween easeOutExpo 0 100 5 -- @ -- -- Keep in mind `tween` must be fed time deltas, not absolute time or -- duration. This is mentioned because the author has made that mistake -- more than once ;) tween :: (Applicative m, Monad m, Fractional t, Ord t)-      => Easing t -> t -> t -> t -> Var m t (Event t)-tween f start end dur = proc dt -> do-    -- Current time as percentage / amount of interpolation (0.0 - 1.0)-    t <- timeAsPercentageOf dur -< dt-    -- Emitted event-    e <- before dur -< dt-    -- Total change in value-    let c = end - start-        b = start-        x = f c t b-    -- Tag the event with the value.-    returnA -< x <$ e+      => Easing t -> t -> t -> t -> Spline t t m t+tween f start end dur = spline start $ timeAsPercentageOf dur ~> var g+    where g t = let c = end - start+                    b = start+                    x = f c t b+                in if t <= 1.0 then Event x else NoEvent --- Creates a tween that performs no interpolation over the duration.+-- | Creates a tween that performs no interpolation over the duration. constant :: (Applicative m, Monad m, Num t, Ord t)-         => a -> t -> Var m t (Event a)-constant value duration = use value $ before duration+         => a -> t -> Spline t a m a+constant value duration = spline value $ use value $ before duration +-- | Varies 0.0 to 1.0 linearly for duration `t` and 1.0 after `t`.+timeAsPercentageOf :: (Applicative m, Monad m, Ord t, Num t, Fractional t)+                   => t -> Var m t t+timeAsPercentageOf t = (\t' -> min 1 (t' / t)) <$> accumulate (+) 0+ ----------------------------------------------------------------------------------- $splines--- If you plan on doing a lot of tweening it's probably easiest to build up--- your tweens as splines using do-notation.--- A spline in this context is a numeric computation that is "smooth" over some--- domain. It is defined in a piecewise manner by sequencing other splines--- together using do-notation.--- You can then run the spline, transforming it back into a continuous--- varying value.+-- $writing+-- To create your own tweens just write a function that takes a start+-- value, end value and a duration and return an event stream. -- -- @--- thereAndBack = execSpline 0 $ do---   x <- tweenTo easeOutExpo 0 100 1---   tweenTo easeOutExpo x 0 1+-- tweenInOutExpo s e d = execSpline s $ do+--     x <- tween easeInExpo s e (d/2)+--     tween easeOutExpo x e (d/2) -- @ ----------------------------------------------------------------------------------- |-tweenTo :: (Applicative m, Monad m, Fractional t, Ord t)-        => Easing t -> t -> t -> t -> Spline m t t t-tweenTo f start end dur = spline start $ tween f start end dur---- | Varies 0.0 to 1.0 linearly for duration `t` and 1.0 after `t`.-timeAsPercentageOf :: (Applicative m, Monad m, Ord t, Num t, Fractional t)-                   => t -> Var m t t-timeAsPercentageOf t = proc dt -> do-    t' <- accumulate (+) 0 -< dt-    returnA -< min 1 (t' / t)- -- | An easing function. The parameters or often named `c`, `t` and `b`, -- where `c` is the total change in value over the complete duration -- (endValue - startValue), `t` is the current percentage of the duration
src/Example.hs view
@@ -1,68 +1,62 @@ module Main where  import Control.Varying-import Control.Varying.Time as Time -- time is not auto-exported import Control.Applicative import Text.Printf  -- | A simple 2d point type.-data Point = Point { x :: Float-                   , y :: Float+data Point = Point { px :: Float+                   , py :: 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 :: (Applicative m, 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+-- An exponential tween back and forth from 0 to 100 over 2 seconds that+-- loops forever. This spline takes float values of delta time as input,+-- outputs the current x value at every step and would result in () if it+-- terminated.+tweenx :: (Applicative m, Monad m) => Spline Float Float m ()+tweenx = do+    -- Tween from 0 to 100 over 1 second+    x <- tween easeOutExpo 0 100 1+    -- Chain another tween back to the starting position+    _ <- tween easeOutExpo x 0 1+    -- Loop forever+    tweenx --- A quadratic tween back and forth from 0 to 100 over 2 seconds.-tweeny :: (Applicative m, Monad m) => Var m Float Float-tweeny =-    tween easeOutQuad 0 100 1 `andThenE` tween easeOutQuad 100 0 1 `andThen` tweeny+-- A quadratic tween back and forth from 0 to 100 over 2 seconds that never+-- ends.+tweeny :: (Applicative m, Monad m) => Spline Float Float m ()+tweeny = do+    y <- tween easeOutQuad 0 100 1+    _ <- tween easeOutQuad y 0 1+    tweeny --- Our time signal.+-- Our time signal that provides delta time samples. time :: Var IO a Float time = deltaUTC +-- | Our Point value that varies over time continuously in x and y.+backAndForth :: Var IO a Point+backAndForth =+    -- Turn our splines back into continuous value streams. We must provide+    -- a starting value since splines are not guaranteed to be defined at+    -- their edges.+    let x = execSpline 0 tweenx+        y = execSpline 0 tweeny+    in+    -- Construct a varying Point that takes time as an input.+    (Point <$> x <*> y)+        -- Stream in a time signal using the 'plug left' combinator.+        -- We could similarly use the 'plug right' (~>) function+        -- and put the time signal before the construction above. This is needed+        -- because the tween streams take time as an input.+        <~ time+ 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)+                          printf "\nPoint %03.1f %03.1f" (px point) (py point)                           loop vNext 
varying.cabal view
@@ -10,15 +10,15 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.1.5.0+version:             0.2.0.0  -- A short (one-line) description of the package.-synopsis:            FRP through varying values and monadic splines.+synopsis:            FRP through value streams and monadic splines.  -- A longer description of the package. description:         Varying is a FRP implentation aimed at providing a-                     simple way to describe values that change over some domain.-                     It allows monadic, applicative or arrow notation and has+                     simple way to describe values that change over a domain.+                     It allows monadic, applicative and arrow notation and has                      convenience functions for tweening.  -- URL for the project homepage or repository.