Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Yampa AFRP Introduction

478 views

Published on

In this talk I introduced Yampa, the AFRP framework in Haskell, and the Quake-like game made by it. The content convers the basic of Functional Reactive Programming, Haskell Arrow, Yampa itself, time-space leak, etc.

  • Login to see the comments

  • Be the first to like this

Yampa AFRP Introduction

  1. 1. Introduction to FRP with a Haskell Implemented, Quake- like Game Functional Thursday #2 snowmantw@gmail.com Link to this slide: http://bit.ly/sntw-ypai
  2. 2. Frag Haskell Yampa OpenGL Quake-like FPS Game Mun Hon Cheong 2005 License: GPL GitHub Mirror bit.ly/sntw-frag
  3. 3. Snowmantw a Programming Language Enthusiast Haskell JavaScript Rust C/C++ Python Ruby Implemented GitHub Profile github.com/ snowmantw
  4. 4. Outline Yampa & FRP Signal Signal Function Space-Time Leak Arrow Arrow Syntax Event Switch Programming with Yampa Yampa www.haskell.org/ haskellwiki/Yampa (not official logo)
  5. 5. Functional Reactive Programming Signal vs. Event
  6. 6. It's all about time & value Functional Reactive Programming H 0 1 E L 2 3 4 5 6 6.5 LO Signal a ≈ Time → a ( 0, 'H') ( 1, 'E') ( 2, 'L') ( 6, 'L') ( 6.5, 'O')
  7. 7. Time will be an implicit input in FRP program: Functional Reactive Programming x = (1/2) * ((integral (vr + vl)) * cos θ) θ = (1/l) * (integral (vr - vl))
  8. 8. function program() { }; Time will be an implicit input in FRP program: Functional Reactive Programming draw(mouse.x, mouse.y)
  9. 9. function program() { }; Time will be an implicit input in FRP program: Functional Reactive Programming draw(mouse.x, mouse.y) The abstraction absorbed all explicit "event" handling
  10. 10. Time will be an implicit input in FRP program: Functional Reactive Programming x integral, +, cos... a ( t0 ) a ( t1 ) a ( t2 ) a ( t3 ) a ( tN ) a ( .... ) b ( t0 ) b ( t1 ) b ( t2 ) b ( t3 ) b ( .... ) x:: Time → Double x = (1/2) * ( (integral (vr + vl)) * cos θ) b ( tN )
  11. 11. Note that the `integral` is stateful (rely on time): Functional Reactive Programming x:: Time → Double x = (1/2) * ( (integral (vr + vl)) * cos θ) t = N, integral (vr + vl)t from 0 to N ... t = 2, integral (vr + vl)t from 0 to 2 t = 1, integral (vr + vl)t from 0 to 1 t = 0, integral (vr + vl)t from 0 to 0
  12. 12. In order to perform stateful computations, we must represent our signals in FRP as streams: Functional Reactive Programming newtype S a = S ([DTime] → [a]) newtype C a = C (a, DTime → C a) integralS :: Double → S Double → S Double integralC :: Double → C Double → C Double x = integralS 0 (vr + vl), where vr & vl are Signals x = integralC 0 (vr + vl), where vr & vl are Signals
  13. 13. In fact we can't touch any signal in Yampa. We can only compose Signal Functions f [ state (t) ] a ( t ) b ( t ) Signal Function SF:: Signal a → Signal b f:: SF a b
  14. 14. f:: SF a b The `state (t)` summarizes input history: same `f` handle every `a` in different time SF:: Signal a → Signal b f [ state (t) ] a ( t0 ) a ( t1 ) a ( t2 ) a ( t3 ) a ( tN ) a ( .... ) b ( t0 ) b ( t1 ) b ( t2 ) b ( t3 ) b ( tN ) b ( .... ) Signal Function
  15. 15. "Space-Time Leak" Why Signal Functions ?
  16. 16. Space-Time Leak in FRP It means that old records got heaped up and occurs the memory due to our expressions had been expanded improperly. An analogous example repeat x = λx → x : repeat x repeat x = λx → let xs = x:xs in xs Leaks No-Leaks
  17. 17. Space-Time Leak in FRP repeat x = λx → x : repeat x repeat 3 ↪ (λx → x : repeat x) (3) ↪ 3 : repeat 3 ↪ 3 : (λx → x : repeat x) (3) ↪ 3 : 3 : repeat 3 ↪ 3 : 3 : (λx → x : repeat x) (3) ↪ 3 : 3 : 3 : repeat 3 ↪ ... It must create new nodes for every `repeat 3`
  18. 18. Space-Time Leak in FRP repeat x = λx → let xs = x:xs in xs repeat 3 ↪ (λx → let xs = x:xs in xs) (3) ↪ xs, where `xs` was defined as above: ↪ 3: xs, where `xs` was defined as above: ↪ 3: 3: xs, where `xs` was defined as above: ↪ 3: 3: 3: xs, where `xs` was defined as above: ↪ ... The `let` bind the same `xs` "reference" in every expanded expression, thus there is no need to create new nodes in memory.
  19. 19. Space-Time Leak in FRP Even though this is just an analogous example, but a similar idea is in Arrow: class Arrow a ⇒ ArrowLoop a where loop :: a (b,d) (c,d) → a b c instance ArrowLoop (→ ) where loop f b = let (c,d) = f (b,d) in c And Yampa uses Arrow to prevent space- time leaks, especially the ArrowLoop.
  20. 20. Space-Time Leak in FRP RECURSIVE CODES MAY DESTRUCT YOUR MIND
  21. 21. Space-Time Leak in FRP A practical example: This example will show that space-time leak may happen when a computation is stateful ( based on time ) The Exponential Function
  22. 22. Space-Time Leak in FRP Because in practical systems we only care about how to compute on continuous streams of values, we can represent our Signals as streams in two forms: newtype S a = S ([DTime] → [a]) newtype C a = C (a, DTime → C a) -- delta time, for sampling type DTime = Double The later one will expand its second (C a) to make a continuing stream.
  23. 23. Space-Time Leak in FRP And the integral functions: integralS :: Double → S Double → S Double integralS i (S f) = S (λdts → scanl (+) i (zipWith (∗) dts (f dts))) integralC :: Double → C Double → C Double integralC i (C p) = C (i, λdt→integralC (i + fst p ∗ dt) (snd p dt)) We assume that delta time is fixed, which is impractical in real system, where it will depends on processor speed, computational load, interrupts, and so on
  24. 24. Space-Time Leak in FRP Remember that the integral need to accumulate each values at every DTime: DTime
  25. 25. That's why it need to expand the stream while evaluation: e = integralC 1 e = integralC i:1 (C p):e=integralC 1 e=... ↪ C (1, λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) ↪ C (1, λdt→integralC (1 + 1 ∗ dt) (snd p dt) ) Space-Time Leak in FRP p fst P integralC :: Double → C Double → C Double integralC i (C p) = C (i, λdt→integralC (i + fst p ∗ dt) (snd p dt))
  26. 26. That's why it need to expand the stream while evaluation: e = integralC 1 e = integralC i:1 (C p):e=integralC 1 e=... ↪ C (1, λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) ↪ C (1, λdt→integralC (1 + 1 ∗ dt) (snd p dt) ) Space-Time Leak in FRP p snd p
  27. 27. That's why it need to expand the stream while evaluation: e = integralC 1 e = integralC i:1 (C p):e=integralC 1 e=... ↪ C (1, λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) ↪ C (1, λdt→integralC (1 + 1 ∗ dt) (sndp dt) ) Space-Time Leak in FRP p snd p
  28. 28. That's why it need to expand the stream while evaluation: e = integralC 1 e = integralC i:1 (C p):e=integralC 1 e=... ↪ C (1, λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) ↪ C (1, λdt→integralC (1 + 1 ∗ dt) (sndp dt) ) ↪ C (1, q ) Space-Time Leak in FRP p snd p
  29. 29. Now we may want to "run" the stream to see what will happen: run :: C Double → [Double] run (C p) = fst p : run (snd p dt) Space-Time Leak in FRP
  30. 30. Now we may want to "run" the stream to see what will happen: run e, where run (C p) = fst p : run (snd p dt) ↪ run C (1, q ), because e = C (1, q ); then evaluate the run: ↪ 1 : run (q dt) ↪ 1 : run ((λdt→integralC (1 + 1 ∗ dt) (q dt) ) dt) ↪ 1 : run (integralC (1 + 1 ∗ dt) (q dt) ) ↪ let's expand the horrible q now... Space-Time Leak in FRP
  31. 31. run e, where run (C p) = fst p : run (snd p dt) ↪ run C (1, q ), because e = C (1, q ); then evaluate the run: ↪ 1 : run (q dt) ↪ 1 : run ((λdt→integralC (1 + 1 ∗ dt) (qdt) ) dt) ↪ 1 : run (integralC (1 + 1 ∗ dt) (q dt) ) ↪ 1 : run (C ( (1 + 1 ∗ dt), (λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) (dt) ) Space-Time Leak in FRP
  32. 32. run e, where run (C p) = fst p : run (snd p dt) ↪ run C (1, q ), because e = C (1, q ); then evaluate the run: ↪ 1 : run (q dt) ↪ 1 : run ((λdt→integralC (1 + 1 ∗ dt) (qdt) ) dt ↪ 1 : run (integralC (1 + 1 ∗ dt) (q dt) ) ↪ 1 : run (C ( (1 + 1 ∗ dt), (λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) (dt) ) ↪ 1 : run (C ( (1 + 1 ∗ dt), (λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) (dt) ) Space-Time Leak in FRP new P new Q
  33. 33. ↪ 1 : run (C ( (1 + 1 ∗ dt), (λdt→integralC (1 + fst p ∗ dt) (snd p dt) ) (dt) ) ↪ 1 : run (C ( (1 + 1 ∗ dt), q )) ↪ 1 : run ((1 + 1 ∗ dt): run (q dt)) ↪ ... Space-Time Leak in FRP This leads to O(n) space ,and O(n2 ) time similar to the simplifier `repeat` example We hope to reduce it to O(Const) space, and O(n) time to compute it
  34. 34. Space-Time Leak in FRP The main issue here is the progress of evaluation can't recognize this: Is the same with: Just like the `repeat` example f = λdt → integralC (1 + dt) (f dt) f = λdt → let x = integralC (1 + dt) x in x
  35. 35. Space-Time Leak in FRP And we can compare them by diagrams: f = λdt → integralC (1 + dt) (f dt) f = λdt → let x = integralC (1 + dt) x in x
  36. 36. Space-Time Leak in FRP In the `repeat` example: repeat x = λx → x : repeat x repeat x = λx → let xs = x:xs in xs
  37. 37. Space-Time Leak in FRP So, in Yampa, we can't touch and handle signals directly, and need to use predefined combinators to compose our program. This can greatly reduce possible leaks, and keep our program is still similar with the most intuitive version. e = integralC 1 e e = proc () → do rec e ← integral 1 ↢e returnA ↢ e
  38. 38. Space-Time Leak in FRP integralSF :: Double → SF Double Double integralSF i = SF (λx → (i, λdt → integralSF (i + dt ∗ x))) integralC :: Double → C Double → C Double integralC i (C p) = C (i, λdt→integralC (i + fst p ∗ dt) (snd p dt)) Versus the previous version: Our integral function now become: Signal handling become implicit. We now raise customized functions to SFs.
  39. 39. Space-Time Leak in FRP integralSF :: Double → SF Double Double integralSF i = SF (λx → (i, λdt → integralSF (i + dt ∗ x))) Now integralSF need be embedded in Arrow structure to feed input in & run it: e = proc () → do rec e ← integral 1 ↢e returnA ↢ e runSF:: SF () Double → [Double] runSF e
  40. 40. Back to Yampa Yampa & AFRP Signal Signal Function Space-Time Leak Arrow Arrow Syntax Event Switch Programming with Yampa Yeah ! Just escaped from the black hole !
  41. 41. Yampa constructs the whole system by combining Signal Functions Combine Signal Functions gf a b c h:: SF a c
  42. 42. Yampa constructs the whole system by combining Signal Functions Combine Signal Functions gf a b c ... and there's already a natural mechanism to achieve this in Haskell
  43. 43. Yampa constructs the whole system by combining Signal Functions Combine Signal Functions gf a b c ( ⋙):: SF a b → SF b c → SF a c "Composition" in Control.Arrow
  44. 44. So Yampa is actually an AFRP framework, not only a FRP framework. Combine Signal Functions gf a b c ( ⋙):: SF a b → SF b c → SF a c "Composition" in Control.Arrow
  45. 45. Arrow We're here: Typeclassopedia www.haskell.org/ haskellwiki/ Typeclassopedia
  46. 46. Arrow Basics "Unlike Monad and Applicative, whose types only reflect their output, the type of an Arrow computation reflects both its input and output" ( ≫= ):: M a → (a → M b) → M b ( ⋙ ):: A a b → A b c → A a c
  47. 47. Arrow Basics In Monad the binding generates a contexted value like `IO String` from an opaque function , and it can output such values without feeding any input ( ≫= ):: M a → (a → M b) → M b
  48. 48. Arrow Basics In Monad the binding generates a contexted value like `IO String` from an opaque function , and it can output such values without feeding any input ( ≫= ):: M a → (a → M b) → M b When you got a composed `IO String`, you don't need to feed it any input to get the output. The "input" is already encapsulated in the Monad. Ex: readFile "/tmp/foo.txt" :: IO String
  49. 49. Arrow Basics Arrows, on the other hand, can only be composed by other arrow combinators, and keep it still crystal clear after the composition ( ⋙ ):: A a b → A b c → A a c
  50. 50. Arrow Basics Arrows, on the other hand, can only be composed by other arrow combinators, and keep it still crystal clear after the composition ( ⋙ ):: A a b → A b c → A a c You can't get any meaningful value without executing the composed Arrow, which will also require you to feed it an input value. Ex: let area = runF ( pow ⋙ mulpi ) r
  51. 51. Arrow Basics So Arrows are just like pipelines, and Monads are more like pipeline plus self-contained pumps
  52. 52. There are many combinators in Control.Arrow Arrow Basics Compose First f g f Split f g f Loop ( self-feedback )
  53. 53. They will make your application like circuits Arrow Basics
  54. 54. Back to Yampa Yampa & AFRP Signal Signal Function Space-Time Leak Arrow Arrow Syntax Event Switch Programming with Yampa Yampa www.haskell.org/ haskellwiki/Yampa (not official logo)
  55. 55. Using Arrows without some syntax sugars will make programs a bit very ugly Arrow Syntax proc x → do y ← f ↢ x+1 g ← 2*y let z = x+y t ← h ↢ x*z returnA ↢ t+z arr (λ x → (x, x)) ⋙ first (arr ( x → x+1) ⋙ f) ⋙ arr ( (y, x) → (y, (x, y))) ⋙ first (arr ( y → 2*y) ⋙ g) ⋙ arr snd ⋙ arr ( (x, y) → let z = x+y in ((x, z), z)) ⋙ first (arr ( (x, z) → x*z) ⋙ h) ⋙ arr ( (t, z) → t+z) ⋙ returnA http://www.haskell.org/ghc/docs/6.12.3/html/ users_guide/arrow-notation.html
  56. 56. Using Arrows without some syntax sugars will make programs a bit very ugly Arrow Syntax proc x → do y ← f ↢ x+1 g ← 2*y let z = x+y t ← h ↢ x*z returnA ↢ t+z proc <pattern> = λ→ <pattern> <pattern> ← <arrf> ↢<expr> ≈ let <pattern> = <arrf> <expr> rec <do block> = ArrowLoop http://stackoverflow.com/questions/5405850/how- does-the-haskell-rec-keyword-work
  57. 57. In Yampa, Event is just a Maybe-like type, representing discrete signals Event data Event a = NoEvent | Event a tag:: Event a → b → Event b We usually use events to trigger switchers, which will change the structure of our system dynamically.
  58. 58. Arrows will make your application like circuits. But you own a dynamic system now, not a static one. Switches Time 0Time 1Time 2Time 3Time 4Time 5Time 6Time 7Time ...Time N
  59. 59. This means circuits won't change unless we introduce Switches Switches Normal signals will be SFs' input; only events will go through the line toward the `k` function with data `mng`. If so the continuation function `k` will spawn a new SF or kill old SFs in the system.
  60. 60. A pseudo example shows how switches works Switches f Kin out System @ T0 1 SF inside a Switch. Switch will let normal signal pass f Kin out System @ T1 `f` generate an Event Spawn, rather than a Signal with data Spawn f Kin out System @ T1 `K` captured the event, and generate a new SF `g` g
  61. 61. A pseudo example shows how switches works Switches f Kin out System @ T1 Then `K` put the new SF in our system. g System @ T2 Now we've 2 SFs and inputs will be dispatched to them all f Kin out g
  62. 62. A pseudo example shows how switches works Switches f Kin out System @ T3 `g` trigger a Kill event with id 'f' g Kill Kin out System @ T3 `K` will kill the SF `f` g f Kin out System @ T4 Done. This shows our system will change by time. g Note: we omitted many details to keep this example clean enough. For instance, we can't kill named SFs after all. They're actually IL Objects.
  63. 63. Switches, more switches... ( cry ) Switches
  64. 64. Switches, more switches... ( cry ) Switches
  65. 65. Switches, more switches... ( cry ) Switches http://www.haskell.org/haskellwiki/ Yampa/switch
  66. 66. How is it possible to use these stuff making a 3D game ? Switches
  67. 67. Programming with Yampa Game Objects Route Kill or Spawn dpSwitch Yampa Acrade http://bit.ly/sntw-ypa
  68. 68. Game objects, like dragons, weapons, players and NPCs are just SFs which receive inputs like the position and velocity, and output the new, updated GameStates Game Objects fin out g
  69. 69. Game objects, like dragons, weapons, players and NPCs are just SFs which receive inputs like the position and velocity, and output the new, updated GameStates Game Objects type Object = SF ObjInput ObjOutput From the file "Object.hs" in the game Frag.
  70. 70. Object inputs in Frag: Game Objects data ObjInput = ObjInput { oiHit :: !(Event [(ILKey,ObsObjState)]), oiMessage :: !(Event [(ILKey,Message)]), oiCollision :: !Camera, oiCollisionPos :: !(Double,Double,Double), oiOnLand :: !Bool, oiGameInput :: !GameInput, oiVisibleObjs :: !(Event [(ILKey,ObsObjState)]) }
  71. 71. Object outputs in Frag: Game Objects data ObjOutput = ObjOutput { ooObsObjState :: !ObsObjState, ooSendMessage :: !(Event [(ILKey,(ILKey,Message))]), ooKillReq :: (Event ()), ooSpawnReq :: (Event [ILKey->Object]) }
  72. 72. A simple game object from Yampa Arcade Game Objects data SimpleGunState = SimpleGunState { sgsPos :: Position2, sgsVel :: Velocity2, sgsFired :: Event () } type SimpleGun = SF GameInput SimpleGunState Source code: http://hackage.haskell.org/package/SpaceInvaders
  73. 73. A simple game object from Yampa Arcade Game Objects gun GameInput Mouse Position Mouse Button Keyboard Input Calculate new position and velocity of the gun SimpleGunState sgsPos sgsVel sgsFired Event
  74. 74. In fact we don't define a SF. We define a SF generator : Game Objects simpleGun :: Position2 → SimpleGun simpleGun (Point2 x0 y0) = proc gi → do (Point2 xd _) ← ptrPos ↢ gi rec let ad = 10 * (xd - x) - 5 * v v ← integral ↢ clampAcc v ad {- ...... -} returnA -< SimpleGunState { sgsPos = (Point2 x y0), sgsVel = (vector2 v 0), sgsFired = fire }
  75. 75. This allow us to embed it into our circuits and change the initial value as we need to: Game Objects game g nAliens vydAlien score0 = proc gi -> do rec oos <- game' objs0 -< (gi, oos {- oosp -}) {- ...... -} returnA -< ((score, map ooObsObjState (elemsIL oos)), (newRound `tag` (Left score)) `lMerge` (gameOver `tag` (Right score))) where objs0 = listToIL (gun (Point2 0 50))
  76. 76. Now we have game objects. Then we've to use a `route` function to pair each object with an input. Route route:: BSPMap → (GameInput, IL ObjOutput) → IL sf → IL (ObjInput, sf) From the file "Game.hs" in the game Frag.
  77. 77. Now we have game objects. Then we've to use a `route` function to pair each object with an input. Route route:: BSPMap → (GameInput, IL ObjOutput) → IL sf → IL (ObjInput, sf) Route will broadcast GameInput to all game object which are like keyboard & mouse state , and handle outputs from game objects to send messages or detect collisions, then only pair it with those related objects.
  78. 78. Now we have game objects. Then we've to use a `route` function to pair each object with an input. Route gun NPC#1 PC Wall R GameInput ObjOutput Decide which objects should be dispatched with current ObjOutputs
  79. 79. Now we have game objects. Then we've to use a `route` function to pair each object with an input. Route route:: BSPMap → (GameInput, IL ObjOutput) → IL sf → IL (ObjInput, sf) `IL a` means a "identity list", which is actually a associate list contains `(ILKey , a)`. Frag use it to store named game objects ( just SFs ) .
  80. 80. Now we have game objects. Then we've to use a `route` function to pair each object with an input. Route route:: BSPMap → (GameInput, IL ObjOutput) → IL sf → IL (ObjInput, sf) Finally the route generate a associate list, pairing each SF with an object input. Note that the original ObjOutput may be converted inside the function.
  81. 81. The function `KillOrSpawn` will capture all events generated by game objects, and find if any kill or spawn events occured. Kill or Spawn killOrSpawn :: (a, IL ObjOutput)→ (Event (IL Object→IL Object)) From the file "Game.hs" in the game Frag.
  82. 82. The function `KillOrSpawn` will capture all events generated by game objects, and find if any kill or spawn events occured. Kill or Spawn killOrSpawn :: (a, IL ObjOutput)→ (Event (IL Object→IL Object))It'll receive lots of object outputs, then generate: 1. NoEvent: do nothing ( rem: Event can be NoEvent ) 2. Kill: with a function that will kill some SFs 3. Spawn: with a function that will spawn new SFs The function will apply on object collections then change it
  83. 83. The function `KillOrSpawn` will capture all events generated by game objects, and find if any kill or spawn events occured. Kill or Spawn f Kin out g ooKillReq Will generate an Event to kill some SFs in the collection f Kin out g ooSpawnReq Will generate an Event to spawn new SFs in the collection
  84. 84. Our `route` and `killOrSpwan` are prepared for the `dpSwitch`, which maintain whole dynamic structure in our program dpSwitch
  85. 85. Our `route` and `killOrSpwan`are prepared for the `dpSwitch`, which maintain whole dynamic structure in our program dpSwitch dpSwitch :: Functor col ⇒ (∀ 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)
  86. 86. dpSwitch :: Functor col ⇒ (∀ 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) The first argument is our routing function. dpSwitch
  87. 87. dpSwitch :: Functor col ⇒ (∀ 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) The second one is the initial collection of game objects. dpSwitch
  88. 88. dpSwitch :: Functor col ⇒ (∀ 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) And the third argument is our `killOrSpawn`. dpSwitch
  89. 89. dpSwitch :: Functor col ⇒ (∀ 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) The fourth function will be invoked while switching event occurs, yielding a new switch function and switch into, based on the collection previous transformed. dpSwitch
  90. 90. dpSwitch :: Functor col ⇒ (∀ 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) This allows the collection to be updated and then switched back in, typically by employing `dpSwitch` again. dpSwitch
  91. 91. Now we have a dynamic structure can compose every piece in our game, so the Quake warrior can roar with firing guns, right ? Some Other Stuff
  92. 92. Still Missing NPC & AI Levels OpenGL Binding ... There is no royal road to Haskell. —Euclid ( typeclassopedia )
  93. 93. Maybe we're still not apt to create a 3D game with the AFRP framework, Yampa, but ideas in FRP & Arrow still inspire us. Conclusion
  94. 94. And FRP is also a generic way to construct any "Event- Driven" like system, from 3D FPS games to HTTP servers. Conclusion http://stackoverflow.com/questions/13486293/ is-frp-a-proper-way-to-implement-most-event-driven-things
  95. 95. Some differences between FRP and so-called "Event- Driven" pattern: Conclusion FRP based on continuing Streams of values, and we compute on them as we compute on a single value. dt1 dt2 dt3 dt4 dt5 sf sf can be primitive SF, composed SF or Switch
  96. 96. Some differences between FRP and so-called "Event- Driven" pattern: Conclusion Event-Driven use individual callbacks to react at every moment the event got triggered. T1 T2 T3 T4 T5 cb cb is a simple function, closure,or class method cb cb cb cb
  97. 97. Conclusion This can be obvious in JavaScript and Node.js, which use Event-Driven as their reactive pattern DOM.addEventListener('click', function(e) { // do something }) fs.readFile( '/tmp/test.txt', function(err, data) { // do something })
  98. 98. Conclusion But some libraries also try to implement FRP paradigm in JavaScript: // from Bacon.js var plus = $("#plus").asEventStream("click").map(1) var minus = $("#minus").asEventStream("click").map(-1) var both = plus.merge(minus)
  99. 99. Conclusion But some libraries also try to implement FRP paradigm in JavaScript: // from Flapjax.js, compiler mode <div> <h1> You caught up <span style="color: white; background-color: black"> {! caughtUpB.toString() !} </span> times</h1> hit up with your mouse </div>
  100. 100. Conclusion But some libraries also try to implement FRP paradigm in JavaScript: http://elm-lang. org/learn/What-is-FRP. elm
  101. 101. Conclusion And you may notice that in FRP, events/signals are handled "globally", but in JavaScript, they're handled "locally": DOM → click, mouse hover... click, mouse hover → Event DOM // FRP // Event-Driven
  102. 102. References There's a lot of resources in Haskell Wiki http://www.haskell.org/haskellwiki/Yampa
  103. 103. References Two useful articles about Yampa and game http://www.cse.unsw.edu.au/~pls/thesis/munc-thesis.pdf http://haskell.cs.yale.edu/wp-content/uploads/2011/01/yampa-arcade. pdf Yampa and robot control http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.5.2886 &rep=rep1&type=pdf
  104. 104. References Space-Time Leak: http://conal.net/blog/posts/trimming-inputs-in-functional-reactive- programming http://cs-www.cs.yale.edu/homes/hl293/download/leak.pdf http://www.cs.ox.ac.uk/ralf.hinze/WG2.8/24/slides/paul.pdf

×