packages feed

reactive 0.9.4 → 0.9.5

raw patch · 6 files changed

+239/−31 lines, 6 files

Files

reactive.cabal view
@@ -1,5 +1,5 @@ Name:                reactive-Version:             0.9.4+Version:             0.9.5 Synopsis:            Simple foundation for functional reactive programming Category:            reactivity, FRP Description:
src/FRP/Reactive/Behavior.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies-           , TypeOperators+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies, TypeOperators+           , StandaloneDeriving, GeneralizedNewtypeDeriving   #-} {-# OPTIONS_GHC -Wall -fno-warn-orphans #-} ----------------------------------------------------------------------@@ -35,25 +35,34 @@ import Data.VectorSpace  import qualified FRP.Reactive.Reactive as R-import FRP.Reactive.Reactive (TimeT, ITime, Event, withTimeE, onceRestE, diffE,joinMaybes,result)+import FRP.Reactive.Reactive+  ( TimeT, EventG, ReactiveG+  , withTimeE,onceRestE,diffE,joinMaybes,result) import FRP.Reactive.Fun+import FRP.Reactive.Improving import FRP.Reactive.Internal.Behavior +type EventI    t = EventG    (Improving t)+type ReactiveI t = ReactiveG (Improving t)+type BehaviorI t = BehaviorG (Improving t) t  -- | Time-specialized behaviors. -- Note: The signatures of all of the behavior functions can be generalized.  Is -- the interface generality worth the complexity?-type Behavior = BehaviorG ITime TimeT+type Behavior = BehaviorI TimeT  -- Synonym for 'Behavior' type Behaviour = Behavior + -- | The identity generalized behavior.  Has value @t@ at time @t@.-time :: Behavior TimeT-time = beh (pure (fun id))+-- +-- > time :: Behavior TimeT+time :: Ord t => BehaviorI t t+time = beh (point (fun id))  -- Turn a reactive value into a discretly changing behavior.-rToB :: R.Reactive a -> Behavior a+rToB :: ReactiveI t a -> BehaviorI t a rToB = beh . fmap pure  -- Then use 'rToB' to promote reactive value functions to behavior@@ -61,7 +70,9 @@  -- | Discretely changing behavior, based on an initial value and a -- new-value event.-stepper :: a -> Event a -> Behavior a+-- +-- >stepper :: a -> Event a -> Behavior a+stepper :: a -> EventI t a -> BehaviorI t a stepper = (result.result) rToB R.stepper  -- Suggested by Robin Green:@@ -75,26 +86,53 @@ -- Looking for a more descriptive name.  -- | Switch between behaviors.-switcher :: Behavior a -> Event (Behavior a) -> Behavior a+-- +-- > switcher :: Behavior a -> Event (Behavior a) -> Behavior a+switcher :: (Ord tr) =>+            BehaviorG tr tf a+         -> EventG tr (BehaviorG tr tf a)+         -> BehaviorG tr tf a b `switcher` eb = beh (unb b `R.switcher` (unb <$> eb))  -- | Snapshots a behavior whenever an event occurs and combines the values -- using the combining function passed.-snapshotWith :: (a -> b -> c) -> Event a -> Behavior b -> Event c+-- +-- > snapshotWith :: (a -> b -> c) -> Event a -> Behavior b -> Event c+-- snapshotWith :: Ord t =>+--                 (a -> b -> c) -> EventG t a -> ReactiveG t b -> EventG t c+snapshotWith :: Ord t =>+                (a -> b -> c)+             -> EventI t a -> BehaviorI t b -> EventI t c snapshotWith h e b = f <$> (withTimeE e `R.snapshot` unb b)  where    f ((a,t),tfun) = h a (tfun `apply` t) ++-- 'snapshotWith' is where tr meets tf.  withTimeE is specialized from+-- withTimeGE, converting the ITime into a TimeT.  This specialization+-- interferes with the generality of several functions in this module,+-- which are therefore now still using 'Behavior' instead of 'BehaviorG'.+-- Figure out how to get generality.++ -- | Snapshot a behavior whenever an event occurs.  See also 'snapshotWith'.-snapshot :: Event a -> Behavior b -> Event (a,b)+-- +-- > snapshot :: Event a -> Behavior b -> Event (a,b)+snapshot :: Ord t => EventI t a -> BehaviorI t b -> EventI t (a,b) snapshot = snapshotWith (,) +-- TODO: tweak withTimeE so that 'snapshotWith' and 'snapshot' can have+-- more general types.  The problem is that withTimeE gives a friendlier+-- kind of time, namely known and finite.  Necessary?+ -- Alternative implementations: --   snapshotWith c e b = uncurry c <$> snapshot e b --   snapshotWith c = (result.result.fmap) (uncurry c) snapshot  -- | Like 'snapshot' but discarding event data (often @a@ is '()').-snapshot_ :: Event a -> Behavior b -> Event b+-- +-- > snapshot_ :: Event a -> Behavior b -> Event b+snapshot_ :: Ord t => EventI t a -> BehaviorI t b -> EventI t b snapshot_ = snapshotWith (flip const)  -- Alternative implementations@@ -102,15 +140,21 @@ -- snapshot_ = (result.result.fmap) snd snapshot  -- | Filter an event according to whether a reactive boolean is true.-whenE :: Event a -> Behavior Bool -> Event a+-- +-- > whenE :: Event a -> Behavior Bool -> Event a+whenE :: Ord t => EventI t a -> BehaviorI t Bool -> EventI t a whenE e = joinMaybes . fmap h . snapshot e  where    h (a,True)  = Just a    h (_,False) = Nothing +-- TODO: Same comment about generality as with snapshot+ -- | Behavior from an initial value and an updater event.  See also -- 'accumE'.-accumB :: a -> Event (a -> a) -> Behavior a+-- +-- > accumB :: a -> Event (a -> a) -> Behavior a+accumB :: a -> EventI t (a -> a) -> BehaviorI t a accumB = (result.result) rToB R.accumR  -- -- | Like 'scanl' for behaviors.  See also 'scanlE'.@@ -125,7 +169,7 @@  ---- The next versions are more continuous: --- type RF a = R.Reactive (Fun TimeT a)+-- type RF a = Reactive (Fun TimeT a)  -- scanlB :: forall a c. (Behavior a -> c -> Behavior a) -> Behavior a --        -> Event c -> Behavior a@@ -145,50 +189,79 @@   -- | Like 'scanl' for behaviors.  See also 'scanlE'.-scanlB :: forall a. (Behavior a -> Behavior a -> Behavior a) -> Behavior a-       -> Event (Behavior a) -> Behavior a+-- +-- > scanlB :: forall a. (Behavior a -> Behavior a -> Behavior a) -> Behavior a+-- >        -> Event (Behavior a) -> Behavior a++-- TODO: generalize scanlB's type++scanlB :: forall a b tr tf. Ord tr =>+          (b -> BehaviorG tr tf a -> BehaviorG tr tf a)+       -> BehaviorG tr tf a+       -> EventG tr b -> BehaviorG tr tf a scanlB plus zero = h  where-   h :: Event (Behavior a) -> Behavior a+   h :: EventG tr b -> BehaviorG tr tf a    h e = zero `switcher` (g <$> onceRestE e)-   g :: (Behavior a, Event (Behavior a)) -> Behavior a+   g :: (b, EventG tr b) -> BehaviorG tr tf a    g (b, e') = b `plus` h e' + -- | Accumulate values from a monoid-valued event.  Specialization of -- 'scanlB', using 'mappend' and 'mempty'.  See also 'monoidE'.-monoidB :: Monoid a => Event (Behavior a) -> Behavior a+-- +-- > monoidB :: Monoid a => Event (Behavior a) -> Behavior a+monoidB :: (Ord tr, Monoid a) => EventG tr (BehaviorG tr tf a)+        -> BehaviorG tr tf a monoidB = scanlB mappend mempty  -- | Like 'sum' for behaviors.-sumB :: AdditiveGroup a => Event a -> Behavior a+-- +-- > sumB :: AdditiveGroup a => Event a -> Behavior a+sumB :: (Ord t, AdditiveGroup a) => EventI t a -> BehaviorI t a sumB = result rToB R.sumR  -- | Start out blank ('Nothing'), latching onto each new @a@, and blanking -- on each @b@.  If you just want to latch and not blank, then use -- 'mempty' for the second event.-maybeB :: Event a -> Event b -> Behavior (Maybe a)+-- +-- > maybeB :: Event a -> Event b -> Behavior (Maybe a)+maybeB :: Ord t =>+          EventI t a -> EventI t b -> BehaviorI t (Maybe a) maybeB = (result.result) rToB R.maybeR  -- | Flip-flopping behavior.  Turns true whenever first event occurs and -- false whenever the second event occurs.-flipFlop :: Event a -> Event b -> Behavior Bool+-- +-- > flipFlop :: Event a -> Event b -> Behavior Bool+flipFlop :: Ord t => EventI t a -> EventI t b -> BehaviorI t Bool flipFlop = (result.result) rToB R.flipFlop  -- | Count occurrences of an event.  See also 'countE'.-countB :: Num n => Event a -> Behavior n+-- +-- > countB :: Num n => Event a -> Behavior n+countB :: (Ord t, Num n) => EventI t a -> BehaviorI t n countB = result rToB R.countR  -- | Euler integral.-integral :: (VectorSpace v, Scalar v ~ TimeT) =>-            Event () -> Behavior v -> Behavior v+-- > integral :: (VectorSpace v, Scalar v ~ TimeT) =>+-- >             Event () -> Behavior v -> Behavior v+-- integral :: (VectorSpace v, Scalar v ~ TimeT) =>+--             EventI t () -> BehaviorI t v -> BehaviorI t v+integral :: (Scalar v ~ t, Ord t, VectorSpace v, Num t) =>+            EventI t a -> BehaviorI t v -> BehaviorI t v integral t = sumB . snapshotWith (*^) (diffE (t `snapshot_` time)) +-- Yow!  That's a mouth full!++ -- TODO: find out whether this integral works recursively.  If not, then -- fix the implementation, rather than changing the semantics.  (No -- "delayed integral".) --  -- Early experiments suggest that recursive integration gets stuck.--- Investigate.+-- Chuan-kai Lin has come up with a new lazier R.snapshotWith, but it+-- leaks when the reactive value changes in between event occurrences.   ---- Comonadic stuff@@ -213,6 +286,20 @@  -- instance Comonad (g :. f) where --   duplicate ++deriving instance (Monoid tr, Monoid tf) => Copointed (BehaviorG tr tf) ++-- ITime and TimeT are not currently monoids.  They can be when I wrap+-- them in the Sum monoid constructor, in which mempty = 0 and mappend =+-- (+).  This monoid change moves us from absolute to relative time.  What+-- do I do for never-occuring futures and terminating events?+++-- instance (Monoid tr, Monoid tf) => Comonad (BehaviorI tf) where+--   duplicate b = b `stepper` undefined+++-- TODO: generalize to BehaviorG   
src/FRP/Reactive/Fun.hs view
@@ -105,6 +105,9 @@   K a'  *** K b'  = K (a',b')   f     *** g     = first f >>> second g +instance Pointed (Fun t) where+  point = K+ instance Monoid t => Copointed (Fun t) where   extract = extract . apply 
+ src/FRP/Reactive/Num-inc.hs view
@@ -0,0 +1,107 @@+----------------------------------------------------------------------+-- Meta-Module :  Num-inc+-- Copyright   :  (c) Conal Elliott 2008+-- License     :  BSD3+-- +-- Maintainer  :  conal@conal.net+-- Stability   :  experimental+-- +-- Instances of Num classes for applicative functors.  To be #include'd+-- after defining APPLICATIVE as the applicative functor name.+-- +-- You'll also have to import 'pure' and 'liftA2' from+-- "Control.Applicative".+----------------------------------------------------------------------++noOv :: String -> String -> a+noOv ty meth = error $ meth ++ ": No overloading for " ++ ty++noFun :: String -> a+noFun = noOv "behavior"++-- Eq & Show are prerequisites for Num, so they need to be faked here+instance Eq (APPLICATIVE b) where+  (==) = noFun "(==)"+  (/=) = noFun "(/=)"++instance Ord b => Ord (APPLICATIVE b) where+  min = liftA2 min+  max = liftA2 max++instance Enum a => Enum (APPLICATIVE a) where+  succ           = fmap succ+  pred           = fmap pred+  toEnum         = pure . toEnum+  fromEnum       = noFun "fromEnum"+  enumFrom       = noFun "enumFrom"+  enumFromThen   = noFun "enumFromThen"+  enumFromTo     = noFun "enumFromTo"+  enumFromThenTo = noFun "enumFromThenTo"++instance Show (APPLICATIVE b) where+  show      = noFun "show"+  showsPrec = noFun "showsPrec"+  showList  = noFun "showList"++instance Num b => Num (APPLICATIVE b) where+  negate      = fmap negate+  (+)         = liftA2 (+)+  (*)         = liftA2 (*)+  fromInteger = pure . fromInteger+  abs         = fmap abs+  signum      = fmap signum++instance (Num a, Ord a) => Real (APPLICATIVE a) where+  toRational = noFun "toRational"++instance Integral a => Integral (APPLICATIVE a) where+  quot      = liftA2 quot+  rem       = liftA2 rem+  div       = liftA2 div+  mod       = liftA2 mod+  quotRem   = (fmap.fmap) unzip (liftA2 quotRem)+  divMod    = (fmap.fmap) unzip (liftA2 divMod)+  toInteger = noFun "toInteger"++instance Fractional b => Fractional (APPLICATIVE b) where+  recip        = fmap recip+  fromRational = pure . fromRational++instance Floating b => Floating (APPLICATIVE b) where+  pi    = pure pi+  sqrt  = fmap sqrt+  exp   = fmap exp+  log   = fmap log+  sin   = fmap sin+  cos   = fmap cos+  asin  = fmap asin+  atan  = fmap atan+  acos  = fmap acos+  sinh  = fmap sinh+  cosh  = fmap cosh+  asinh = fmap asinh+  atanh = fmap atanh+  acosh = fmap acosh++instance RealFrac a => RealFrac (APPLICATIVE a) where+  properFraction = noFun "properFraction"+  truncate       = noFun "truncate"+  round          = noFun "round"+  ceiling        = noFun "ceiling"+  floor          = noFun "floor"++instance RealFloat a => RealFloat (APPLICATIVE a) where+  floatRadix     = noFun "floatRadix"+  floatDigits    = noFun "floatDigits"+  floatRange     = noFun "floatRange"+  decodeFloat    = noFun "decodeFloat"+  encodeFloat    = (fmap.fmap) pure encodeFloat+  exponent       = noFun "exponent"+  significand    = noFun "significand"+  scaleFloat n   = fmap (scaleFloat n)+  isNaN          = noFun "isNaN"+  isInfinite     = noFun "isInfinite"+  isDenormalized = noFun "isDenormalized"+  isNegativeZero = noFun "isNegativeZero"+  isIEEE         = noFun "isIEEE"+  atan2          = liftA2 atan2
src/FRP/Reactive/PrimReactive.hs view
@@ -579,6 +579,11 @@ -- TODO: Reconsider E = F :. R .  Didn't work with absolute time.  What -- about relative time? +instance Ord t => Pointed (ReactiveG t) where+  point = (`stepper` mempty)++-- TODO: I think we can bypass mempty and so eliminate the Ord+-- constraint.  If so, remove Ord tr from 'time' in Behavior.  instance Monoid t => Copointed (ReactiveG t) where   -- extract = extract . rat
src/FRP/Reactive/Reactive.hs view
@@ -94,12 +94,18 @@  -- | Access occurrence times in an event.  See 'withTimeGE' for more -- general notions of time.-withTimeE :: Event a -> Event (a, TimeT)+-- +-- > withTimeE :: Event a -> Event (a, TimeT)+withTimeE :: Ord t =>+             EventG (Improving t) d -> EventG (Improving t) (d, t) withTimeE e = second (exact.timeT) <$> withTimeGE e  -- | Access occurrence times in an event.  Discard the rest.  See also -- 'withTimeE'.-withTimeE_ :: Event a -> Event TimeT+-- +-- > withTimeE_ :: Event a -> Event TimeT+withTimeE_ :: Ord t =>+              EventG (Improving t) d -> EventG (Improving t) t withTimeE_ = (result.fmap) snd withTimeE  timeT :: Ord t => Time t -> t@@ -337,7 +343,7 @@ -- fix the implementation, rather than changing the semantics.  (No -- "delayed integral".) -sumR :: AdditiveGroup v => Event v -> Reactive v+sumR :: Ord t => AdditiveGroup v => EventG t v -> ReactiveG t v sumR = scanlR (^+^) zeroV