my adventure with elm (lambdacon15)
TRANSCRIPT
BOLOGNA 28 march 2015 LambdaCon
Yan Cui (@theburningmonk)my adventure with Elm
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
agenda
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Hi, my name is Yan Cui.
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
I’m not an expert on Elm.
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Function Reactive Programming?
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Value over Time
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Time
Value
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Time
ValueSignal
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
?
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
SignalVariable
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Reactive is Dead, long live composing side effects.
bit.ly/1sb5hCu
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
In computing, reactive programming is a programming paradigm oriented around data flows and the
propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the
underlying execution model will automatically propagate changes through the data flow.
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Scalable
ResilientReplication
High-Availability
Elasticity
Non-Blocking
Asynchronous
Message-Passing
Isolation
ContainmentLocation-Transparency
Loose-Coupling
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Reactive Programming =
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
bit.ly/1sb5hCu
Reactive is Dead, long live composing side effects.
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
“One thing I’m discovering is that transforming data is easier to think about than
maintaining state.” !
- Dave Thomas
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
let y = f(x)
Imperative Functional
x.f()
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
mutation
let y = f(x)
Imperative Functional
x.f()
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Move Up
Move Down
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
private var arrowKeyUp:Bool; private var arrowKeyDown:Bool; !private var platform1:Platform; private var platform2:Platform; private var ball:Ball;
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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; } }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
function keyUp(event:KeyboardEvent):Void { if (event.keyCode == 38) { arrowKeyUp = false; } else if (event.keyCode == 40) { arrowKeyDown = false; } }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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; } }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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; } }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
source files
state changes
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
source files execution
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
source files execution
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
mental model
input state new state behaviour
{ x; y } { x; y-speed }
{ x; y } { x; y+speed }
timer { x; y } { x; y } draw platform
… … … …
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
transformation
let y = f(x)
Imperative Functional
x.f()
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Transformations simplify problem decomposition
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Move Up
Move Down
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
UP { x=0, y=1 } DOWN { x=0, y=-1 } LEFT { x=-1, y=0 } RIGHT { x=1, y=0 }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Rx Dart ElmObservable Stream Signal
= =
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Idea See in Action
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 LambdaCon
Yan Cui (@theburningmonk)my adventure with Elm
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
http://bit.ly/1wV46XS
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Elm Basics
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
add x y = x + y
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
add : Int -> Int -> Intadd x y = x + y
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
calcAngle start end = let distH = end.x - start.x distV = end.y - start.y in atan2 distV distH
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
multiply x y = x * y triple = multiply 3
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
multiply x y = x * y triple = multiply 3
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
f a b c d = … f : Int -> (Int -> (Int -> (Int -> Int)))
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
double list = List.map (\x -> x * 2) list
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
double list = List.map ((*) 2) list
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
tuple1 = (2, “three”) tuple2 = (2, “three”, [4, 5])
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
tuple4 = (,) 2 “three” tuple5 = (,,) 2 “three” [4, 5]
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
x = { age=42, name=“foo” }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
lightweight, labelled data structure
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
x.age x.name
-- 42 -- “foo”
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
x.age x.name
-- 42 -- “foo”
.age x
.name x-- 42 -- “foo”
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
-- clone and update y = { x | name <- "bar" }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
type alias Character = { age : Int, name : String }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
type alias Named a = { a | name : String } type alias Aged a = { a | age : Int }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
lady : Named ( Aged { } ) lady = { name=“foo”, age=42 }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
getName : Named x -> String getName { name } = name
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
getName : Named x -> String getName { name } = name !
getName lady -- “foo”
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
type Status = Flying Pos Speed | Exploding Radius | Exploded
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
aka. “sums-and-products”
data structures
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
type Status = Flying Pos Speed | Exploding Radius | Exploded
sums : choice between variants of a type
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
products : tuple of types
type Status = Flying Pos Speed | Exploding Radius | Exploded
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
filled : Color -> Shape -> Form
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
“…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)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle : Int -> Int -> Float -> Form
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = circle >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = circle >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
circle : Float -> Shape
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
filled : Color -> Shape -> Form
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
Curried!
filled : Color -> Shape -> Form
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> filled (rgb 150 170 150) >> alpha 0.5 >> move (x, y)
Shape -> Form
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Shape) >> (Shape -> Form) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> alpha 0.5 >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> (Form -> Form) >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> (Form -> Form) >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> move (x, y)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> (Form -> Form)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form) >> (Form -> Form)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle x y = (Float -> Form)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
drawCircle : Int -> Int -> (Float -> Form)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
greet name = case name of "Yan" -> “hi, theburningmonk" _ -> “hi, “ ++ name
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
greet name = case name of "Yan" -> “hi, theburningmonk" _ -> “hi, “ ++ name
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
fizzbuzz n = if | n % 15 == 0 -> "fizz buzz" | n % 3 == 0 -> "fizz" | n % 5 == 0 -> "buzz" | otherwise -> show n
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Mouse.position Mouse.clicks
Mouse.isDown …
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Window.dimension Window.width Window.height
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Time.every Time.fps
Time.timestamp Time.delay
…
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Mouse.position : Signal (Int, Int)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Mouse.position : Signal (Int, Int)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Mouse.position : Signal (Int, Int)
(10, 23) (3, 16) (8, 10) (12, 5) (18, 3)
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Keyboard.lastPressed : Signal Int
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Keyboard.lastPressed : Signal Int
H E L L O space
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Keyboard.lastPressed : Signal Int
H E L L O space
72 69 76 76 79 32
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
map : (a -> b) -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
<~
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Signal of num of pixels in window
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(\(w, h) -> w*h) <~ Window.dimensions
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(\(w, h) -> w*h) <~ Window.dimensions
Signal (Int, Int)(Int, Int) -> Int
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(\(w, h) -> w*h) <~ Window.dimensions
Signal (Int, Int)(Int, Int) -> Int
Signal Int
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(10, 10) (15, 10) (18, 12)
100 150 216
(\(w, h) -> w*h) <~ Window.dimensions
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
map2 : (a -> b -> c) -> Signal a -> Signal b -> Signal c
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
~
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(,) <~ Window.width ~ Window.height
Signal Int
a -> b -> (a, b)
Signal Int
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(,) <~ Window.width ~ Window.height
Signal Int
Int -> Int -> (Int, Int)
Signal Int
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
map3 : (a -> b -> c -> d) -> Signal a -> Signal b -> Signal c -> Signal d
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
(,,) <~ signalA ~ signalB ~ signalC
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
map4 : … map5 : … map6 : … map7 : … map8 : …
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp : (a -> b -> b) -> b -> Signal a -> Signal b
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp (\_ n -> n + 1) 0 Mouse.clicks
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp (\_ n -> n + 1) 0 Mouse.clicks
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
foldp (\_ n -> n + 1) 0 Mouse.clicks
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
1 3 42 5
foldp (\_ n -> n + 1) 0 Mouse.clicks
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
UP { x=0, y=1 } DOWN { x=0, y=-1 } LEFT { x=-1, y=0 } RIGHT { x=1, y=0 }
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
merge : Signal a -> Signal a -> Signal a mergeMany : List (Signal a) -> Signal a …
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Js Interop, WebGL
HTML layout, dependency management,
etc.
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
8 segments
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
change
change
no changenot allowed
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
cherry
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
YUM YUM YUM!
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
direction
+1 segment
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 LambdaCon
Yan Cui (@theburningmonk)my adventure with Elm
BOLOGNA 28 march 2015 LambdaCon
Yan Cui (@theburningmonk)my adventure with Elm
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
Demo
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
github.com/theburningmonk/elm-snake
github.com/theburningmonk/elm-missile-command
Missile Command
Snake
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
elm-lang.org/try
debug.elm-lang.org/try
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
the����������� ������������������ not����������� ������������������ so����������� ������������������ great����������� ������������������ things
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
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
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
breaking changes
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon
@theburningmonk
github.com/theburningmonk
theburningmonk.com
Leave your feedback on Joind.in! https://joind.in/13665 !!
BOLOGNA 28 march 2015 - Yan Cui @theburningmonk LambdaCon