Solutions to Problem Set 10 =========================== Written by Paul Hudak in literate Haskell style. November 30, 2004 > module PS10 where > import Arrow Exercises 1-5 from "Arrows, Robots, and Functional Reactive Programming", by Hudak, Courtney, Nilsson, and Peterson. 1. Define (a) "first" in terms of just "arr", "(>>>)", and "(&&&)", (b) "(***)" in terms of just "first", "second", and "(>>>)", and (c) "(&&&)" in terms of just "arr", "(>>>)", and "(***)". Solution: (names changed to prevent conflicts with the Arrrow module) > first' :: Arrow a => a b c -> a (b,d) (c,d) > first' f = (arr fst >>> f) &&& arr snd > > (****) :: Arrow a => a b c -> a b' c' -> a (b,b') (c,c') > f **** g = first f >>> second g > > (&&&&) :: Arrow a => a b c -> a b d -> a b (c,d) > f &&&& g = arr (\b -> (b,b)) >>> (f *** g) 2. Define signal functions "ySF" and "thetaSF" in Yampa that correspond to the definitions of "y" and "theta", respectively, in FRP. Solution: y = (1/2) * integral ((vr + vl) * sin theta) theta = (1/l) * integral (vr - vl) > ySF :: Arrow a => a b Double > ySF = let v = (vrSF &&& vlSF) >>> arr2 (+) > t = thetaSF >>> arr sin > in (v &&& t) >>> arr2 (*) >>> integral >>> arr (/2) > > thetaSF :: Arrow a => a b Double > thetaSF = let v = (vrSF &&& vlSF) >>> arr2 (-) > in v >>> integral >>> arr (/l) 3. Rewrite the definitions of "ySF" and "thetaSF" from the previous exercise using the arrow syntax. Also draw their signal flow diagrams. Solution (untested because Hugs doesn't know arrow syntax): ySF' = proc inp -> do vr <- vrSF -< inp vl <- vlSF -< inp theta <- thetaSF -< inp i <- integral -< (vr+vl) * sin theta returnA -< (i/2) thetaSF' = proc inp do vr <- vrSF -< inp vl <- vlSF -< inp i <- integral -< vr-vl returnA -< (i/l) [ signal diagrams omitted ] 4. Rather than set the wheel speed to zero when the robot gets stuck, negate it instead. Then define "xspd" recursively so that the velocity gets negated every time the robot gets stuck. Solution: > xspd :: Arrow a => Double -> a b Double > xspd v = (constant v &&& rsStuck) `switch` \() -> xspd (-v) 5. Suppose "v :: SF SimbotInput Velocity" represents the scalar velocity of a simbot. If we integrate this velocity, we get a measure of how far the simbot has traveled. Define an alarm that generates an event when either the simbot has traveled more than "d" meters, or it has gotten stuck. Solution: > tooFarOrStuck :: Arrow a => a b (Event ()) > tooFarOrStuck = > let p = v >>> integral > tooFar = (p &&& constant d) >>> arr2 (>) >>> edge > in (tooFar &&& rsStuck) >>> arr2 merge Or, using arrow syntax (untested): tooFarOrStuck = proc inp do p <- (v >>> integral) -< inp s <- rsStuck -< inp a <- edge -< (p>d) return (s `merge` a) --- Type sigs to make all of the above type-check: > integral :: Arrow a => a Double Double > integral = undefined > arr2 :: Arrow a => (b->c->d) -> a (b,c) d > arr2 = undefined > vlSF :: Arrow a => a b Double > vlSF = undefined > vrSF :: Arrow a => a b Double > vrSF = undefined > l :: Double > l = undefined > constant :: Arrow a => c -> a b c > constant = undefined > rsStuck :: Arrow a => a b (Event ()) > rsStuck = undefined > switch :: Arrow a => a b (c, Event d) -> (d -> a b c) -> a b c > switch = undefined > edge :: Arrow a => a Bool (Event ()) > edge = undefined > data Event a = Event a > merge :: Event a -> Event a -> Event a > merge = undefined > d :: Double > d = undefined > v :: Arrow a => a b Double > v = undefined