Advertisement
Guest User

Purescript FRP sample

a guest
Apr 7th, 2017
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. type Time = Number
  2. type Color = String
  3.  
  4. -- any type that has a value, eg Number, is kind `*`
  5. -- Behavior is a type constructor aka "Higher Kinded Type"
  6. -- This is a function that takes an `a`, a type variable
  7. -- and returns a `Behavior`
  8. -- so it has kind `* -> *`
  9.  
  10. newtype Behavior a = Behavior { at :: Time -> a}
  11. at :: forall a. Behavior a -> Time -> a
  12.  
  13. -- this function lets us reify a value `a` at time `t`
  14. at (Behavior {at: bat}) t = bat t
  15.  
  16.  
  17. -- in a pure language, we must carefully manage side-effects,
  18. -- so the compiler knows where the program touches the outside world
  19. -- Here, we define the type of a method that renders to an HTML canvas
  20. class Renderable a where
  21.     render :: forall eff. Context2D -> a -> Eff (canvas :: CANVAS | eff) Unit
  22.  
  23.  
  24. newtype Rectangle = Rectangle { x :: Number, y :: Number, w :: Number
  25.                               , h :: Number, c :: Color
  26.                               }
  27.  
  28. -- let's make our rectangle renderable!
  29. instance renderableRectangle :: Renderable Rectangle where
  30.     render ctx (Rectangle {x,y,w,h,c}) = void do
  31.         setFillStyle c ctx
  32.         fillPath ctx $ rect ctx
  33.             { x: x
  34.             , y: y
  35.             , w: w
  36.             , h: h
  37.             }
  38.  
  39. -- we can define a recursive function to make a list of renderable types
  40. -- as renderable itself
  41. instance renderableList :: Renderable a => Renderable (List a) where
  42.     render ctx renderables = go renderables where
  43.         go Nil = do
  44.             pure unit
  45.         go (b : bs) = void do
  46.             render ctx b
  47.             go bs
  48.  
  49. -- a curried version of the standard requestAnimationFrame (not shown)
  50. foreign import requestAnimationFrame :: forall a eff.
  51.     Window -> (Time -> Eff (dom :: DOM | eff) a) -> Eff (dom :: DOM | eff) Unit
  52.  
  53. -- simple loop that renders a behavior indefinitely
  54. animationLoop :: forall e a. (Renderable a) =>
  55.                  { w :: Window, ctx :: Context2D, width :: Number
  56.                  , height :: Number, b :: Behavior a} -> Time
  57.                    -> Eff (dom :: DOM, canvas :: CANVAS | e) Unit
  58. animationLoop {w, ctx, width, height, b} t =
  59.     let raf = requestAnimationFrame w
  60.         loop t = do
  61.             clearRect ctx { x: 0.0
  62.                         , y: 0.0
  63.                         , w: width
  64.                         , h: height
  65.                         }
  66.             let world = b `at` t
  67.             render ctx world
  68.             raf loop
  69.     in do raf loop
  70.  
  71. -- now let's run an animation. Dropped frames will not impact
  72. -- rectangle location accuracy since behaviors are continuous
  73. main = void $ unsafePartial do
  74.     Just canvas <- getCanvasElementById "canvas"
  75.     w <- window
  76.     ctx <- getContext2D canvas
  77.     width <- getCanvasWidth canvas
  78.     height <- getCanvasHeight canvas
  79.     let sample t = Rectangle { x: 0.01*t
  80.                               , y: 250.0
  81.                               , w: 10.0
  82.                               , h: 300.0
  83.                               , c: "red"
  84.                               }
  85.  
  86.     let b = Behavior { at: sample }
  87.                            
  88.     animationLoop {w:w, ctx:ctx, width:width, height:height, b:b} 0.0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement