my adventure with elm - yan cui - codemotion roma 2015
TRANSCRIPT
Yan Cui !Talk title: My Adventure with Elm [email protected] - GameSys - @theburningmonk
ROME 27-28 march 2015
ROME 27-28 march 2015 – Yan Cui @theburningmonk
agenda
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Hi, my name is Yan Cui.
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
I’m not an expert on Elm.
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Function Reactive Programming?
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Value over Time
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Time
Value
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Time
ValueSignal
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Reactive is Dead, long live composing side effects.
bit.ly/1sb5hCu
ROME 27-28 march 2015 – Yan Cui @theburningmonk
“One thing I’m discovering is that transforming data is easier to think about than
maintaining state.” !
- Dave Thomas
ROME 27-28 march 2015 – Yan Cui @theburningmonk
let y = f(x)
Imperative Functional
x.f()
ROME 27-28 march 2015 – Yan Cui @theburningmonk
mutation
let y = f(x)
Imperative Functional
x.f()
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Move Up
Move Down
ROME 27-28 march 2015 – Yan Cui @theburningmonk
private var arrowKeyUp:Bool; private var arrowKeyDown:Bool; !private var platform1:Platform; private var platform2:Platform; private var ball:Ball;
ROME 27-28 march 2015 – Yan Cui @theburningmonk
function keyDown(event:KeyboardEvent):Void { if (currentGameState == Paused && event.keyCode == 32) { setGameState(Playing); } else if (event.keyCode == 38) { arrowKeyUp = true; } else if (event.keyCode == 40) { arrowKeyDown = true; } }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
function keyUp(event:KeyboardEvent):Void { if (event.keyCode == 38) { arrowKeyUp = false; } else if (event.keyCode == 40) { arrowKeyDown = false; } }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
function everyFrame(event:Event):Void { if(currentGameState == Playing){ if (arrowKeyUp) { platform1.y -= platformSpeed; } if (arrowKeyDown) { platform1.y += platformSpeed; } if (platform1.y < 5) platform1.y = 5; if (platform1.y > 395) platform1.y = 395; } }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
function everyFrame(event:Event):Void { if(currentGameState == Playing){ if (arrowKeyUp) { platform1.y -= platformSpeed; } if (arrowKeyDown) { platform1.y += platformSpeed; } if (platform1.y < 5) platform1.y = 5; if (platform1.y > 395) platform1.y = 395; } }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
source files
state changes
ROME 27-28 march 2015 – Yan Cui @theburningmonk
source files execution
ROME 27-28 march 2015 – Yan Cui @theburningmonk
source files execution
ROME 27-28 march 2015 – Yan Cui @theburningmonk
mental model
input state new state behaviour
{ x; y } { x; y-speed }
{ x; y } { x; y+speed }
timer { x; y } { x; y } draw platform
… … … …
ROME 27-28 march 2015 – Yan Cui @theburningmonk
transformation
let y = f(x)
Imperative Functional
x.f()
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Transformations simplify problem decomposition
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Move Up
Move Down
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
UP { x=0, y=1 } DOWN { x=0, y=-1 } LEFT { x=-1, y=0 } RIGHT { x=1, y=0 }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Platform = {x:Int, y:Int} defaultPlatform = {x=5, y=0} !delta = Time.fps 20 input = Signal.sampleOn delta Keyboard.arrows !cap x = max 5 <| min x 395 !p1 : Signal Platform p1 = foldp (\{x, y} s -> {s | y <- cap <| s.y + 5*y}) defaultPlatform input
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Rx Dart ElmObservable Stream Signal
= =
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Idea See in Action
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Yan Cui !Talk title: My Adventure with Elm [email protected] - GameSys - @theburningmonk
ROME 27-28 march 2015
ROME 27-28 march 2015 – Yan Cui @theburningmonk
http://bit.ly/1wV46XS
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Elm Basics
ROME 27-28 march 2015 – Yan Cui @theburningmonk
add x y = x + y
ROME 27-28 march 2015 – Yan Cui @theburningmonk
add : Int -> Int -> Intadd x y = x + y
ROME 27-28 march 2015 – Yan Cui @theburningmonk
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
ROME 27-28 march 2015 – Yan Cui @theburningmonk
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
ROME 27-28 march 2015 – Yan Cui @theburningmonk
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
ROME 27-28 march 2015 – Yan Cui @theburningmonk
multiply x y = x * y triple = multiply 3
ROME 27-28 march 2015 – Yan Cui @theburningmonk
multiply x y = x * y triple = multiply 3
ROME 27-28 march 2015 – Yan Cui @theburningmonk
f a b c d = … f : Int -> (Int -> (Int -> (Int -> Int)))
ROME 27-28 march 2015 – Yan Cui @theburningmonk
double list = List.map (\x -> x * 2) list
ROME 27-28 march 2015 – Yan Cui @theburningmonk
double list = List.map ((*) 2) list
ROME 27-28 march 2015 – Yan Cui @theburningmonk
tuple1 = (2, “three”) tuple2 = (2, “three”, [4, 5])
ROME 27-28 march 2015 – Yan Cui @theburningmonk
tuple4 = (,) 2 “three” tuple5 = (,,) 2 “three” [4, 5]
ROME 27-28 march 2015 – Yan Cui @theburningmonk
x = { age=42, name=“foo” }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
lightweight, labelled data structure
ROME 27-28 march 2015 – Yan Cui @theburningmonk
x.age x.name
-- 42 -- “foo”
ROME 27-28 march 2015 – Yan Cui @theburningmonk
x.age x.name
-- 42 -- “foo”
.age x
.name x-- 42 -- “foo”
ROME 27-28 march 2015 – Yan Cui @theburningmonk
-- clone and update y = { x | name <- "bar" }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Character = { age : Int, name : String }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type alias Named a = { a | name : String } type alias Aged a = { a | age : Int }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
lady : Named ( Aged { } ) lady = { name=“foo”, age=42 }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
getName : Named x -> String getName { name } = name
ROME 27-28 march 2015 – Yan Cui @theburningmonk
getName : Named x -> String getName { name } = name !
getName lady -- “foo”
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type Status = Flying Pos Speed | Exploding Radius | Exploded
ROME 27-28 march 2015 – Yan Cui @theburningmonk
aka. “sums-and-products”
data structures
ROME 27-28 march 2015 – Yan Cui @theburningmonk
type Status = Flying Pos Speed | Exploding Radius | Exploded
sums : choice between variants of a type
ROME 27-28 march 2015 – Yan Cui @theburningmonk
products : tuple of types
type Status = Flying Pos Speed | Exploding Radius | Exploded
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
filled : Color -> Shape -> Form
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
“…a clean design is one that supports visual thinking so people can meet their informational needs with a minimum of
conscious effort.” !
- Daniel Higginbotham (www.visualmess.com)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y radius = radius |> circle |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
2. top-to-bottom
1. left-to-right
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle : Int -> Int -> Float -> Form
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = circle >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = circle >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
circle : Float -> Shape
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
filled : Color -> Shape -> Form
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
Curried!
filled : Color -> Shape -> Form
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
Shape -> Form
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> alpha 0.5 >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> (Form -> Form) >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> (Form -> Form) >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> move (x, y)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> (Form -> Form)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form) >> (Form -> Form)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle x y = (Float -> Form)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
drawCircle : Int -> Int -> (Float -> Form)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
greet name = case name of "Yan" -> “hi, theburningmonk" _ -> “hi, “ ++ name
ROME 27-28 march 2015 – Yan Cui @theburningmonk
greet name = case name of "Yan" -> “hi, theburningmonk" _ -> “hi, “ ++ name
ROME 27-28 march 2015 – Yan Cui @theburningmonk
fizzbuzz n = if | n % 15 == 0 -> "fizz buzz" | n % 3 == 0 -> "fizz" | n % 5 == 0 -> "buzz" | otherwise -> show n
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Mouse.position Mouse.clicks
Mouse.isDown …
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Window.dimension Window.width Window.height
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Time.every Time.fps
Time.timestamp Time.delay
…
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Mouse.position : Signal (Int, Int)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Mouse.position : Signal (Int, Int)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Mouse.position : Signal (Int, Int)
(10, 23) (3, 16) (8, 10) (12, 5) (18, 3)
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Keyboard.lastPressed : Signal Int
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Keyboard.lastPressed : Signal Int
H E L L O space
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Keyboard.lastPressed : Signal Int
H E L L O space
72 69 76 76 79 32
ROME 27-28 march 2015 – Yan Cui @theburningmonk
map : (a -> b) -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
<~
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Signal of num of pixels in window
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(\(w, h) -> w*h) <~ Window.dimensions
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(\(w, h) -> w*h) <~ Window.dimensions
Signal (Int, Int)(Int, Int) -> Int
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(\(w, h) -> w*h) <~ Window.dimensions
Signal (Int, Int)(Int, Int) -> Int
Signal Int
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(10, 10) (15, 10) (18, 12)
100 150 216
(\(w, h) -> w*h) <~ Window.dimensions
ROME 27-28 march 2015 – Yan Cui @theburningmonk
map2 : (a -> b -> c) -> Signal a -> Signal b -> Signal c
ROME 27-28 march 2015 – Yan Cui @theburningmonk
~
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(,) <~ Window.width ~ Window.height
Signal Int
a -> b -> (a, b)
Signal Int
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(,) <~ Window.width ~ Window.height
Signal Int
Int -> Int -> (Int, Int)
Signal Int
ROME 27-28 march 2015 – Yan Cui @theburningmonk
map3 : (a -> b -> c -> d) -> Signal a -> Signal b -> Signal c -> Signal d
ROME 27-28 march 2015 – Yan Cui @theburningmonk
(,,) <~ signalA ~ signalB ~ signalC
ROME 27-28 march 2015 – Yan Cui @theburningmonk
map4 : … map5 : … map6 : … map7 : … map8 : …
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp (\_ n -> n + 1) 0 Mouse.clicks
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp (\_ n -> n + 1) 0 Mouse.clicks
ROME 27-28 march 2015 – Yan Cui @theburningmonk
foldp (\_ n -> n + 1) 0 Mouse.clicks
ROME 27-28 march 2015 – Yan Cui @theburningmonk
1 3 42 5
foldp (\_ n -> n + 1) 0 Mouse.clicks
ROME 27-28 march 2015 – Yan Cui @theburningmonk
UP { x=0, y=1 } DOWN { x=0, y=-1 } LEFT { x=-1, y=0 } RIGHT { x=1, y=0 }
ROME 27-28 march 2015 – Yan Cui @theburningmonk
merge : Signal a -> Signal a -> Signal a mergeMany : List (Signal a) -> Signal a …
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Js Interop, WebGL
HTML layout, dependency management,
etc.
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
8 segments
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
change
change
no changenot allowed
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
cherry
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
YUM YUM YUM!
ROME 27-28 march 2015 – Yan Cui @theburningmonk
direction
+1 segment
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Demo
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
github.com/theburningmonk/elm-snake
github.com/theburningmonk/elm-missile-command
Missile Command
Snake
ROME 27-28 march 2015 – Yan Cui @theburningmonk
elm-lang.org/try
debug.elm-lang.org/try
ROME 27-28 march 2015 – Yan Cui @theburningmonk
the����������� ������������������ not����������� ������������������ so����������� ������������������ great����������� ������������������ things
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Type error between lines 63 and 85: case gameState of
NotStarted -> if | userInput == Space -> Started (defaultSnake,Nothing)
| True -> gameState Started ({segments,direction},cherry) -> let arrow = case userInput
of Arrow arrow -> arrow
_ -> {x = 0, y = 0} newDirection = getNewDirection
arrow direction newHead = getNewSegment
(List.head segments) newDirection newTail = List.take
((List.length segments) - 1) segments
(w,h) = windowDims isGameOver = (List.any
(\t -> t == newHead) newTail) ||
(((fst newHead) > ((toFloat w) / 2)) || (((snd newHead) > ((toFloat h) / 2)) || (((fst newHead) <
((toFloat (-w)) / 2)) || ((snd newHead) <
((toFloat (-h)) / 2))))) in if | isGameOver -> NotStarted
| True -> Started
({segments = newHead :: newTail, direction = newDirection},
cherry) ! Expected Type: {}
Actual Type: Snake.Input
cryptic error messages
ROME 27-28 march 2015 – Yan Cui @theburningmonk
breaking changes
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
ROME 27-28 march 2015 – Yan Cui @theburningmonk
@theburningmonk
github.com/theburningmonk
theburningmonk.com
http://hire.jobvite.com/m?3OHq4hwL
F#
C#
AWSErlang
Docker
micro-services
elasticsearch
redisGoogle
AppEngine
Google BigQuery
PostSharpNeo4j
Python DevOps
PagerDuty
NewRelic
ROME 27-28 march 2015 – Yan Cui @theburningmonk
Leave your feedback on Joind.in! https://joind.in/14145 !!