My adventure with elm (LambdaCon15)

Post on 16-Jul-2015

1,181 views 0 download

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