Download presentation
Presentation is loading. Please wait.
Published byCameron Short Modified over 9 years ago
1
Christof Douma Functional Reactive Programming
2
What are reactive systems? Transformational vs. Reactive ● Transformational systems compute output from an input and then terminate. Examples: UUAG, GHC, Latex. ● Reactive systems respond to stimuli in order to bring about desirable effects in their environment. Examples: Proxima, Mozilla, Quake, Space Invaders.
3
Why Functional Reactive Programming? ● Functional programming has usually been applied to build transformational systems. ● Usually imperative paradigms are adopted when building reactive systems. ● FRP is a new paradigm to program reactive systems in a functional language. ● Useful for Embedded Domain Specific Languages
4
What is FRP Good for? ● Applications of FRP (EDSL) – FVision [Reid, Peterson, Hudak and Hager] Visiual tracking – Fran [Elliott and Hudak] Interactive animation – FranTk [Sage], Fruit [Courtney] GUI – Frob [Peterson, Hager, Hudak and Elliott] Robotics moveXY (sin time) 0 charlotte charlotte = importBitmap “charlotte.bmp”
5
FRP Pardigm ● FRP has two key abstractions ● Continuous time-varying values ● Discrete streams of events ● Uses combinators that hide detail about timing and synchronization Signal a = Time -> a
6
Signal Functions ● Signals can be manipulated directly ● Problem: Time- and space-leaks – Time leaks occur in real-time systems when a computation does not “keep up” with the current time, this requiring “catching up” at a later time. ● Solution: Use Signal Functions – Signals are not fist class values anymore SF a b = Signal a -> Signal b
7
Signal Function Example ● An example, the sin function: Floating a => SF a a time
8
Composing FRP programs ● Complex programs can be build by composing simpler programs ● Current implementation uses the Arrow class – change of name: AFRP arr :: (a -> b) -> SF a b (>>>) :: SF a b -> SF b c -> SF a c first :: SF a b -> SF (a,c) -> SF (b,c)
9
AFRP Example ● Travel returns a SF that generates a constant signal v while the distance d hasn't yet been travelled. travel :: Distance -> Velocity -> SF Velocity Velocity travel d v = integral >>> arr (\d2 -> if d2 < d then v else 0) (note the lack of explicite time)
10
Composing AFRP programs ● more Arrow combinators second :: SF a b -> SF (c,a) (c,b) ( SF a b -> SF a c (&&&) :: SF a b -> SF a c -> SF a (b,c) (***) :: SF a b -> SF c d -> SF (a,c) (b,d) loop :: SF (a,c) (b,c) -> SF a b
11
Arrows vs Monads ● IO Programs are a composition of actions with the details of the state are hidden from the user. It is ran at the top level by an interpreter ● AFRP programs is a composition of signal function with the details of the signals hidden from the user. It is ran at the top level by an interpreter ● Monads composition must be linear ● Arrows composition is not linear
12
AFRP Primitive Signal Functions identity :: SF a a constant :: n -> SF a b integral :: SF Double Double derivative:: SF Double Double time :: SF a Time arr2 :: (a -> b -> c) -> SF (a,b) c
13
Discrete Events ● Events can be user input as well as domain- specific sensors, interrupts, etc. ● Events are represented as signals of the Event datatype Event a = NoEvent | Event a edge :: SF Bool (Event ()) hold :: SF (Event a) a
14
Discrete events (2) ● Operations on event streams include – mapping, filtering, merging, etc. – Switching of reactive behavior (next slide) tag :: Event a -> b -> Event b mergeBy :: (a->a->a) -> Event a -> Event a -> Event a accum :: a -> SF (Event (a->a)) (Event a) after :: Time -> b -> SF a (Event b) repeatedly :: Time -> b -> SF a (Event b)
15
Switching ● read as: 'Behave as sf1 until the first event in es occurs. Then bind the event value to e and behave as sf2.' ● Note: The time flow restart when switch is made into the new SF. switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b sf1 && es `switch` (\e -> sf2)
16
Switch Example travel :: Distance -> Velocity -> SF Velocity Velocity travel d v = switch (constant v &&& wayTooFar) (\_ -> constant 0) where wayTooFar = integral >>> arr (>=d) >>> edge switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b (&&&) :: SF a b -> SF a c -> SF a (b,c)
17
Arrow Syntax tr avel d v = forward `switch` stop where stop _ = contant 0 forward = proc iv -> do td <- integral -< iv e = d) returnA -< (v,e) ● Preprocessor translate arrow symtax into Haskell with first, arr, (<<<) and loop Arrow operators
18
Switch Semantics ● Two questions arise about switching semantics: – Does the switch happen exactly at the event time, or infinitesimally after? – Does the switch happen just for the first event, or for every event in an event stream? 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
19
Recursive Signal Functions ● Suppose incrVel :: SF RobotInput (Event ()) generates 'commands' to increments the velocity of a robot. ● concider: vel :: Velocity -> SF RobotInput Velocity vel v0 = proc inp -> do rec e <- incrVel -< inp v <- drSwitch (constant v0) -< (inp, e `tag` constant (v+1)) returnA -< v ● Note that vel is recursively defined, which requires: – The use of the rec keyword – The use of a delayed switch (drSwitch)
20
Running the program ● To execute a program we need to connect the SF to the outside world ● Approximate the Continuous-time model reactimate :: IO (DTime,a)-- sense -> (b -> IO ())-- actuate -> SF a b -> IO ()
21
AFrob Programming Robots with AFRP
22
AFrob ● AFRob is an EDSL - written in AFRP - for programming robots. It includes a robot simulator. ● AFRob models robots with two wheels and two independent motors. These are called SimBots. ● Each SimBot has a bumper switch, a range object finder, an animate object tracker. ● Each SimBot is controlled by a Signal Function
23
Differential Drive Mobile Robot θ l vlvl vrvr y x ● The Equations for the x position are:
24
Simbot X position ● Assume that: xSF :: SF SimbotInput Distance xSF = proc inp -> do vr <- vrSF -< inp vl <- vlSF -< inp theta <- thetaSF -< inp i <- integral -< (vr+vl) * cos theta returnA -< (i/2) vrSF,vlSF :: SF SimbotInput Speed thetaSF :: SF SimbotInput Angle ● we can write x(t) in AFRP as:
25
Robot Input Signals class HasRobotStatus i where rsBattStat :: i -> BatteryStatus rsStuck :: i -> Bool class HasOdometry i where odometryPosition :: i -> Position2 odometryHeading :: i -> Heading instance HasRobotStatus SimbotInput instance HasOdometry SimbotInput
26
Robot Output Signals class MergeableRecord o => HasDiffDrive o where ddBrake :: MR o ddVelDiff :: Velocity -> Velocity -> MR o ddVelTR :: Velocity -> RotVel -> MR o class MergeableRecord o => HasTextConsole o where tcoPrintMessage :: Event String -> MR o mrFinalize :: MergeableRecord o => MR o -> o mrMerge :: MergeableRecord o => MR o -> MR o -> MR o instance HasDiffDrive SimbotOutput instance HasTextConsole SimbotOutput
27
Robot Properties class HasRobotProperties i where rpType :: i -> RobotType rpId :: i -> RobotId rpDiameter :: i -> Length rpAccMax :: i -> Acceleration rpWSMax :: i -> Speed instance HasRobotProperties SimbotProperties ● Static information about the capabilities of a robot
28
Robot Controllers Type SimbotController = SimbotProperties -> SF SimbotInput SimbotOutput rcStop :: SimbotController rcStop rps = constant (mrFinalize ddBrake) rcBlind :: SimbotController rcBlind rps = let max = rpWSMax rps in constant (mrFinalize $ ddVelDiff (max/2) (max/2)) ● A stationary simbot: ● A simbot that goes at ½ of the maximum speed:
29
Running in Circles rcTurn :: Velocity -> SimbotController rcTurn vel rps = let vMax = rpWSMax rps rMax = 2 * (vMax – vel) / rpDiameter rps in constant (mrFinalize $ ddVelTR vel rMax) ● A simbot that goes at ½ of the maximum speed: ● Simbots cannot turn arbitrarily fast – it depends on their speed. The maximum rotational velocity is:
30
Another Example Robot Controller rdDumb :: RobotController rcDumb rps = proc sbi -> do iAmStuck <- rsStuck -< sbi rec let sig = (sbi, iAmStuck `tag` constant (-velo)) velo <- drSwitch (constant maxVel) -< sig returnA -< mrFinalize $ ddVelDiff velo velo where maxVel = rpWSMax rps drSwitch :: SF a b -> SF (a,Event (SF a b)) b tag :: Event a -> b -> Event b ● A simbot which reverses when hitting something
31
Running in a Virtual World runSim :: Maybe WorldTemplate ->-- virtual world SimbotController ->-- simbot A’s SimbotController ->-- simbot B’s IO ()-- does the work type WorldTemplate = [ObjectTemplate] data ObjectTemplate = OTBlock { otPos :: Position2 }-- Square obstacle | OTVWall { otPos :: Position2 }-- Vertical wall | OTHWall { otPos :: Position2 }-- Horizontal wall | OTBall { otPos :: Position2 }-- Ball | OTSimbotA { otRId :: RobotId,-- Simbot A robot otPos :: Position2, otHdng :: Heading } | OTSimbotB {... }-- Simbot B robot
32
Demo Program module MyRobotShow where import AFrob-- AFrob library import AFrobRobotSim-- the simulator main :: IO () main = runSim (Just world) rcA rcB world :: WorldTemplate world =... rcA, rcB, rcB1, rcB2:: SimbotController rcA =...-- controller for simbot A’s rcB rProps = case rpId rProps of-- controller for simbot B’s 1 -> rcB1 rProps-- (showing here how to deal 2 -> rcB2 rProps-- with multiple simbots)
33
● where r is the range-finder reading, d is the desired distance, and K p and K d are the proportionate and derivative gains, respectively. Follow the Wall ● To follow a wall, we use a range finder to sense the distance to the wall. ● It can be shown (for small deviations) that the rotational velocity should be:
34
More Robot Input Signals class Has RangeFinder i where rfRange :: i -> Angle -> Distance rfMaxRange :: i -> Distance -- derived range finders rfFront, rfBack, rfLeft, rfRight :: HasRangeFinder i => i -> Distance instance HasRangeFinder SimbotInput ● A simbot has a range finder ● A range finder finds the nearest object in a given direction
35
Follow the Wall Controller ● This leads to the controller: rcFollowLeftWall :: Velocity -> Distance -> SimbotController rcFollowLeftWall v d _ = proc sbi -> do let r = rfLeft sbi dr <- derivative -< r let omega = kp*(r-d) + kd*dr kd = 5 kp = v*(kd^2)/4-- achieves “critical damping” returnA -< mrFinalize (ddVelTR v (lim 0.2 omega))
36
Systems with Dynamic Structure ● All objects are Signal Functions ● Objects can be added and removed ● We need combinators that can change the signal network at runtime – So far we modelled systems where the signal network is static
37
Dynamic Collections in AFRP ● AFRP has special combinators for this purpose parB :: Functor col => col (SF a b) -> SF a (col b) par :: Functor col => (forall sf.(a->col sf->col (b,sf))) -> col (SF b c) -> SF a (col c) pSwitch :: Functor col => (forall sf.(a->col sf->col (b,sf))) -> col (SF b c) -> SF (a,col c) (Event d) -> (col (SF b c) -> d -> SF a (col c)) -> SF a (col c)
38
Learn more? ● Look at the webiste – http://www.haskell.org/yampa/ http://www.haskell.org/yampa/ – http://www.haskell.org/frp/ http://www.haskell.org/frp/ ● example application – The Yampa Arcade [Antony Courtney, Henrik Nilsson and John Peterson, 2003] – Robot Soccer (included in the yampa package)
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.