Yampa 0.9.3 → 0.9.5
raw patch · 4 files changed
+157/−87 lines, 4 filesnew-uploaderPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG +13/−0
- Yampa.cabal +6/−4
- src/FRP/Yampa.hs +103/−59
- src/FRP/Yampa/Event.hs +35/−24
+ CHANGELOG view
@@ -0,0 +1,13 @@+2014-04-07 Ivan Perez <ivan.perez@keera.es>++ * Yampa.cabal: version bump (0.9.5)+ * Adds CHANGELOG to cabal file++2014-04-07 Ivan Perez <ivan.perez@keera.es>++ * Yampa.cabal: new maintainer, version bump (0.9.4).+ * src/: documentation is exposed so that Haddock can process it+ * No interface changes++Copyright (c) 2003, Henrik Nilsson, Antony Courtney and Yale University.+All rights reserved.
Yampa.cabal view
@@ -1,10 +1,10 @@ name: Yampa-version: 0.9.3+version: 0.9.5 cabal-version: >= 1.6 license: BSD3 license-file: LICENSE author: Henrik Nilsson, Antony Courtney-maintainer: George Giorgidze (giorgidze@gmail.com)+maintainer: Ivan Perez (ivan.perez@keera.co.uk) homepage: http://www.haskell.org/haskellwiki/Yampa category: Reactivity, FRP synopsis: Library for programming hybrid systems.@@ -30,8 +30,10 @@ examples/Elevator/Elevator.hs, examples/Elevator/TestElevatorMain.hs, examples/TailgatingDetector/TailgatingDetector.hs,- examples/TailgatingDetector/TestTGMain.hs+ examples/TailgatingDetector/TestTGMain.hs, + CHANGELOG+ library hs-source-dirs: src ghc-options : -O3 -Wall -fno-warn-name-shadowing@@ -57,4 +59,4 @@ source-repository head type: git- location: git://github.com/giorgidze/Yampa.git+ location: git://github.com/ivanperez-keera/Yampa.git
src/FRP/Yampa.hs view
@@ -135,24 +135,27 @@ -- For optimization arrPrim, arrEPrim, --- Basic signal functions+-- * Signal functions++-- ** Basic signal functions identity, -- :: SF a a constant, -- :: b -> SF a b localTime, -- :: SF a Time time, -- :: SF a Time, Other name for localTime. --- Initialization+-- ** Initialization (-->), -- :: b -> SF a b -> SF a b, infixr 0 (>--), -- :: a -> SF a b -> SF a b, infixr 0 (-=>), -- :: (b -> b) -> SF a b -> SF a b infixr 0 (>=-), -- :: (a -> a) -> SF a b -> SF a b infixr 0 initially, -- :: a -> SF a a --- Simple, stateful signal processing+-- ** Simple, stateful signal processing sscan, -- :: (b -> a -> b) -> b -> SF a b sscanPrim, -- :: (c -> a -> Maybe (c, b)) -> c -> b -> SF a b --- Basic event sources+-- * Events+-- ** Basic event sources never, -- :: SF a (Event b) now, -- :: b -> SF a (Event b) after, -- :: Time -> b -> SF a (Event b)@@ -167,13 +170,39 @@ edgeJust, -- :: SF (Maybe a) (Event a) edgeBy, -- :: (a -> a -> Maybe b) -> a -> SF a (Event b) --- Stateful event suppression+-- ** Stateful event suppression notYet, -- :: SF (Event a) (Event a) once, -- :: SF (Event a) (Event a) takeEvents, -- :: Int -> SF (Event a) (Event a) dropEvents, -- :: Int -> SF (Event a) (Event a) --- Basic switchers+-- ** Pointwise functions on events+ noEvent, -- :: Event a+ noEventFst, -- :: (Event a, b) -> (Event c, b)+ noEventSnd, -- :: (a, Event b) -> (a, Event c)+ event, -- :: a -> (b -> a) -> Event b -> a+ fromEvent, -- :: Event a -> a+ isEvent, -- :: Event a -> Bool+ isNoEvent, -- :: Event a -> Bool+ tag, -- :: Event a -> b -> Event b, infixl 8+ tagWith, -- :: b -> Event a -> Event b,+ attach, -- :: Event a -> b -> Event (a, b), infixl 8+ lMerge, -- :: Event a -> Event a -> Event a, infixl 6+ rMerge, -- :: Event a -> Event a -> Event a, infixl 6+ merge, -- :: Event a -> Event a -> Event a, infixl 6+ mergeBy, -- :: (a -> a -> a) -> Event a -> Event a -> Event a+ mapMerge, -- :: (a -> c) -> (b -> c) -> (a -> b -> c) + -- -> Event a -> Event b -> Event c+ mergeEvents, -- :: [Event a] -> Event a+ catEvents, -- :: [Event a] -> Event [a]+ joinE, -- :: Event a -> Event b -> Event (a,b),infixl 7+ splitE, -- :: Event (a,b) -> (Event a, Event b)+ filterE, -- :: (a -> Bool) -> Event a -> Event a+ mapFilterE, -- :: (a -> Maybe b) -> Event a -> Event b+ gate, -- :: Event a -> Bool -> Event a, infixl 8++-- * Switching+-- ** Basic switchers switch, dSwitch, -- :: SF a (b, Event c) -> (c -> SF a b) -> SF a b rSwitch, drSwitch, -- :: SF a b -> SF (a,Event (SF a b)) b kSwitch, dkSwitch, -- :: SF a b@@ -181,7 +210,8 @@ -- -> (SF a b -> c -> SF a b) -- -> SF a b --- Parallel composition and switching over collections with broadcasting+-- ** Parallel composition and switching+-- *** Parallel composition and switching over collections with broadcasting parB, -- :: Functor col => col (SF a b) -> SF a (col b) pSwitchB,dpSwitchB, -- :: Functor col => -- col (SF a b)@@ -193,7 +223,7 @@ -- -> SF (a, Event (col (SF a b)->col (SF a b))) -- (col b) --- Parallel composition and switching over collections with general routing+-- *** Parallel composition and switching over collections with general routing par, -- Functor col => -- (forall sf . (a -> col sf -> col (b, sf))) -- -> col (SF b c)@@ -210,13 +240,14 @@ -- -> SF (a, Event (col (SF b c) -> col (SF b c))) -- (col c) --- Wave-form generation+-- * Discrete to continuous-time signal functions+-- ** Wave-form generation old_hold, -- :: a -> SF (Event a) a hold, -- :: a -> SF (Event a) a dHold, -- :: a -> SF (Event a) a trackAndHold, -- :: a -> SF (Maybe a) a --- Accumulators+-- ** Accumulators old_accum, -- :: a -> SF (Event (a -> a)) (Event a) old_accumBy, -- :: (b -> a -> b) -> b -> SF (Event a) (Event b) old_accumFilter, -- :: (c -> a -> (c, Maybe b)) -> c@@ -229,57 +260,35 @@ accumFilter, -- :: (c -> a -> (c, Maybe b)) -> c -- -> SF (Event a) (Event b) --- Delays+-- * Delays+-- ** Basic delays old_pre, old_iPre, pre, -- :: SF a a iPre, -- :: a -> SF a a --- Timed delays+-- ** Timed delays delay, -- :: Time -> a -> SF a a --- Integration and differentiation- integral, -- :: VectorSpace a s => SF a a-- derivative, -- :: VectorSpace a s => SF a a -- Crude!- imIntegral, -- :: VectorSpace a s => a -> SF a a+-- * State keeping combinators --- Loops with guaranteed well-defined feedback+-- ** Loops with guaranteed well-defined feedback loopPre, -- :: c -> SF (a,c) (b,c) -> SF a b loopIntegral, -- :: VectorSpace c s => SF (a,c) (b,c) -> SF a b --- Pointwise functions on events- noEvent, -- :: Event a- noEventFst, -- :: (Event a, b) -> (Event c, b)- noEventSnd, -- :: (a, Event b) -> (a, Event c)- event, -- :: a -> (b -> a) -> Event b -> a- fromEvent, -- :: Event a -> a- isEvent, -- :: Event a -> Bool- isNoEvent, -- :: Event a -> Bool- tag, -- :: Event a -> b -> Event b, infixl 8- tagWith, -- :: b -> Event a -> Event b,- attach, -- :: Event a -> b -> Event (a, b), infixl 8- lMerge, -- :: Event a -> Event a -> Event a, infixl 6- rMerge, -- :: Event a -> Event a -> Event a, infixl 6- merge, -- :: Event a -> Event a -> Event a, infixl 6- mergeBy, -- :: (a -> a -> a) -> Event a -> Event a -> Event a- mapMerge, -- :: (a -> c) -> (b -> c) -> (a -> b -> c) - -- -> Event a -> Event b -> Event c- mergeEvents, -- :: [Event a] -> Event a- catEvents, -- :: [Event a] -> Event [a]- joinE, -- :: Event a -> Event b -> Event (a,b),infixl 7- splitE, -- :: Event (a,b) -> (Event a, Event b)- filterE, -- :: (a -> Bool) -> Event a -> Event a- mapFilterE, -- :: (a -> Maybe b) -> Event a -> Event b- gate, -- :: Event a -> Bool -> Event a, infixl 8+-- ** Integration and differentiation+ integral, -- :: VectorSpace a s => SF a a --- Noise (random signal) sources and stochastic event sources+ derivative, -- :: VectorSpace a s => SF a a -- Crude!+ imIntegral, -- :: VectorSpace a s => a -> SF a a++-- * Noise (random signal) sources and stochastic event sources noise, -- :: noise :: (RandomGen g, Random b) => -- g -> SF a b noiseR, -- :: noise :: (RandomGen g, Random b) => -- (b,b) -> g -> SF a b occasionally, -- :: RandomGen g => g -> Time -> b -> SF a (Event b) --- Reactimation+-- * Reactimation reactimate, -- :: IO a -- -> (Bool -> IO (DTime, Maybe a)) -- -> (Bool -> b -> IO Bool)@@ -295,7 +304,9 @@ -- -> (DTime,Maybe a) -- -> IO Bool --- Embedding (tentative: will be revisited)+-- * Embedding++-- (tentative: will be revisited) DTime, -- [s] Sampling interval, always > 0. embed, -- :: SF a b -> (a, [(DTime, Maybe a)]) -> [b] embedSynch, -- :: SF a b -> (a, [(DTime, Maybe a)]) -> SF Double b@@ -340,7 +351,7 @@ -- switch would need to remember the record, since it is the only place -- where signal functions get started. So it wouldn't cost all that much. --- Time is used both for time intervals (duration), and time w.r.t. some+-- | Time is used both for time intervals (duration), and time w.r.t. some -- agreed reference point in time. Conceptually, Time = R, i.e. time can be 0 -- or even negative. type Time = Double -- [s]@@ -349,13 +360,15 @@ -- DTime is the time type for lengths of sample intervals. Conceptually, -- DTime = R+ = { x in R | x > 0 }. Don't assume Time and DTime have the -- same representation.- type DTime = Double -- [s] - -- Representation of signal function in initial state. -- (Naming: "TF" stands for Transition Function.) +-- | Signal function that transforms a signal carrying values of some type 'a'+-- into a signal carrying values of some type 'b'. You can think of it as+-- (Signal a -> Signal b). A signal is, conceptually, a+-- function from 'Time' to value. data SF a b = SF {sfTF :: a -> Transition a b} @@ -1753,29 +1766,31 @@ -- Basic event sources ------------------------------------------------------------------------------ --- Event source that never occurs.+-- | Event source that never occurs. never :: SF a (Event b) never = SF {sfTF = \_ -> (sfNever, NoEvent)} --- Event source with a single occurrence at time 0. The value of the event+-- | Event source with a single occurrence at time 0. The value of the event -- is given by the function argument. now :: b -> SF a (Event b) now b0 = (Event b0 --> never) --- Event source with a single occurrence at or as soon after (local) time q+-- | Event source with a single occurrence at or as soon after (local) time /q/ -- as possible.-after :: Time -> b -> SF a (Event b)+after :: Time -- ^ The time /q/ after which the event should be produced+ -> b -- ^ Value to produce at that time+ -> SF a (Event b) after q x = afterEach [(q,x)] ---- Event source with repeated occurrences with interval q.+-- | Event source with repeated occurrences with interval q. -- Note: If the interval is too short w.r.t. the sampling intervals, -- the result will be that events occur at every sample. However, no more -- than one event results from any sampling interval, thus avoiding an -- "event backlog" should sampling become more frequent at some later -- point in time.+ -- !!! 2005-03-30: This is potentially a bit inefficient since we KNOW -- !!! (at this level) that the SF is going to be invarying. But afterEach -- !!! does NOT know this as the argument list may well be finite.@@ -2004,7 +2019,10 @@ (x' : rxs) --- A rising edge detector. Useful for things like detecting key presses.+-- | A rising edge detector. Useful for things like detecting key presses.+-- It is initialised as /up/, meaning that events occuring at time 0 will+-- not be detected.+ -- Note that we initialize the loop with state set to True so that there -- will not be an occurence at t0 in the logical time frame in which -- this is started.@@ -3126,10 +3144,33 @@ -- the reactimation loop and return to its caller. -- sf ......... Signal function to reactimate. -reactimate :: IO a- -> (Bool -> IO (DTime, Maybe a))- -> (Bool -> b -> IO Bool)- -> SF a b+-- | Convenience function to run a signal function indefinitely, using+-- a IO actions to obtain new input and process the output.+--+-- This function first runs the initialization action, which provides the+-- initial input for the signal transformer at time 0.+--+-- Afterwards, an input sensing action is used to obtain new input (if any) and+-- the time since the last iteration. The argument to the input sensing function+-- indicates if it can block. If no new input is received, it is assumed to be+-- the same as in the last iteration.+--+-- After applying the signal function to the input, the actuation IO action+-- is executed. The first argument indicates if the output has changed, the second+-- gives the actual output). Actuation functions may choose to ignore the first+-- argument altogether. This action should return True if the reactimation+-- must stop, and False if it should continue.+--+-- Note that this becomes the program's /main loop/, which makes using this+-- function incompatible with GLUT, Gtk and other graphics libraries. It may also+-- impose a sizeable constraint in larger projects in which different subparts run+-- at different time steps. If you need to control the main+-- loop yourself for these or other reasons, use 'reactInit' and 'react'.++reactimate :: IO a -- ^ IO initialization action+ -> (Bool -> IO (DTime, Maybe a)) -- ^ IO input sensing action+ -> (Bool -> b -> IO Bool) -- ^ IO actuaction (output processing) action+ -> SF a b -- ^ Signal function -> IO () reactimate init sense actuate (SF {sfTF = tf0}) = do@@ -3308,3 +3349,6 @@ -- But what do we do if the inner system runs more slowly than the -- outer one? Then we need to extrapolate the output from the -- inner system, and we have the same problem with events AGAIN!++-- Vim modeline+-- vim:set tabstop=8 expandtab:
src/FRP/Yampa/Event.hs view
@@ -94,20 +94,24 @@ -- Also note that it unfortunately is possible to partially break the -- abstractions through judicious use of e.g. snap and switching. +-- | A single possible event occurrence, that is, a value that may or may+-- not occur. Events are used to represent values that are not produced+-- continuously, such as mouse clicks (only produced when the mouse is clicked,+-- as opposed to mouse positions, which are always defined). data Event a = NoEvent | Event a deriving (Show) --- Make the NoEvent constructor available. Useful e.g. for initialization,+-- | Make the NoEvent constructor available. Useful e.g. for initialization, -- ((-->) & friends), and it's easily available anyway (e.g. mergeEvents []). noEvent :: Event a noEvent = NoEvent --- Suppress any event in the first component of a pair.+-- | Suppress any event in the first component of a pair. noEventFst :: (Event a, b) -> (Event c, b) noEventFst (_, b) = (NoEvent, b) --- Suppress any event in the second component of a pair.+-- | Suppress any event in the second component of a pair. noEventSnd :: (a, Event b) -> (a, Event c) noEventSnd (a, _) = (a, NoEvent) @@ -169,19 +173,22 @@ -- Utility functions similar to those available for Maybe ------------------------------------------------------------------------------ --- An event-based version of the maybe function.+-- | An event-based version of the maybe function. event :: a -> (b -> a) -> Event b -> a event a _ NoEvent = a event _ f (Event b) = f b +-- | Extract the value from an event. Fails if there is no event. fromEvent :: Event a -> a fromEvent (Event a) = a fromEvent NoEvent = usrErr "AFRP" "fromEvent" "Not an event." +-- | Tests whether the input represents an actual event. isEvent :: Event a -> Bool isEvent NoEvent = False isEvent (Event _) = True +-- | Negation of 'isEvent'. isNoEvent :: Event a -> Bool isNoEvent = not . isEvent @@ -190,14 +197,16 @@ -- Event tagging ------------------------------------------------------------------------------ --- Tags an (occurring) event with a value ("replacing" the old value).+-- | Tags an (occurring) event with a value ("replacing" the old value). tag :: Event a -> b -> Event b e `tag` b = fmap (const b) e +-- | Tags an (occurring) event with a value ("replacing" the old value). Same+-- as 'tag' with the arguments swapped. tagWith :: b -> Event a -> Event b tagWith = flip tag --- Attaches an extra value to the value of an occurring event.+-- | Attaches an extra value to the value of an occurring event. attach :: Event a -> b -> Event (a, b) e `attach` b = fmap (\a -> (a, b)) e @@ -214,57 +223,58 @@ -- !!! Finally: mergeEvents is left-biased, but this is not reflected in -- !!! its name. --- Left-biased event merge.+-- | Left-biased event merge (always prefer left event, if present). lMerge :: Event a -> Event a -> Event a le `lMerge` re = event re Event le --- Right-biased event merge.+-- | Right-biased event merge (always prefer right event, if present). rMerge :: Event a -> Event a -> Event a le `rMerge` re = event le Event re --- Unbiased event merge: simultaneous occurrence is an error.+-- | Unbiased event merge: simultaneous occurrence is an error. merge :: Event a -> Event a -> Event a merge = mergeBy (usrErr "AFRP" "merge" "Simultaneous event occurrence.") --- Event merge paramterezied on the conflict resolution function.+-- | Event merge parameterized by a conflict resolution function. mergeBy :: (a -> a -> a) -> Event a -> Event a -> Event a mergeBy _ NoEvent NoEvent = NoEvent mergeBy _ le@(Event _) NoEvent = le mergeBy _ NoEvent re@(Event _) = re mergeBy resolve (Event l) (Event r) = Event (resolve l r) ---- A generic event merge utility:+-- | A generic event merge-map utility that maps event occurrences,+-- merging the results. The first three arguments are mapping functions,+-- the third of which will only be used when both events are present.+-- Therefore, 'mergeBy' = 'mapMerge' 'id' 'id' mapMerge :: (a -> c) -> (b -> c) -> (a -> b -> c) -> Event a -> Event b -> Event c-mapMerge _ _ _ NoEvent NoEvent = NoEvent-mapMerge lf _ _ (Event l) NoEvent = Event (lf l)-mapMerge _ rf _ NoEvent (Event r) = Event (rf r)+mapMerge _ _ _ NoEvent NoEvent = NoEvent+mapMerge lf _ _ (Event l) NoEvent = Event (lf l)+mapMerge _ rf _ NoEvent (Event r) = Event (rf r) mapMerge _ _ lrf (Event l) (Event r) = Event (lrf l r) -- Merging of a list of events; foremost event has priority. mergeEvents :: [Event a] -> Event a mergeEvents = foldr lMerge NoEvent ---- Collects simultaneous event occurrences; no event if none.+-- | Collects simultaneous event occurrences; no event if none. catEvents :: [Event a] -> Event [a] catEvents eas = case [ a | Event a <- eas ] of [] -> NoEvent as -> Event as ---- Join (conjucntion) of two events.+-- | Join (conjucntion) of two events. Only produces an event+-- if both events exist. joinE :: Event a -> Event b -> Event (a,b) joinE NoEvent _ = NoEvent joinE _ NoEvent = NoEvent joinE (Event l) (Event r) = Event (l,r) --- Split event carrying pairs into two events.+-- | Split event carrying pairs into two events. splitE :: Event (a,b) -> (Event a, Event b) splitE NoEvent = (NoEvent, NoEvent) splitE (Event (a,b)) = (Event a, Event b)@@ -274,13 +284,14 @@ -- Event filtering ------------------------------------------------------------------------------ --- Filter out events that don't satisfy some predicate.+-- | Filter out events that don't satisfy some predicate. filterE :: (a -> Bool) -> Event a -> Event a-filterE p e@(Event a) = if (p a) then e else NoEvent+filterE p e@(Event a) = if p a then e else NoEvent filterE _ NoEvent = NoEvent --- Combined event mapping and filtering.+-- | Combined event mapping and filtering. Note: since 'Event' is a 'Functor',+-- see 'fmap' for a simpler version of this function with no filtering. mapFilterE :: (a -> Maybe b) -> Event a -> Event b mapFilterE _ NoEvent = NoEvent mapFilterE f (Event a) = case f a of@@ -288,7 +299,7 @@ Just b -> Event b --- Enable/disable event occurences based on an external condition.+-- | Enable/disable event occurences based on an external condition. gate :: Event a -> Bool -> Event a _ `gate` False = NoEvent e `gate` True = e