Slide 1

Slide 1 text

Introduction to Elm

Slide 2

Slide 2 text

Martin Rechsteiner @rechsteiner

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

We’re hiring! Senior mobile developer Oslo & Trondheim Front-end developer Oslo & Trondheim

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Humans make mistakes

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

A functional language that compiles to JavaScript

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Focus on user experience

Slide 14

Slide 14 text

Elm is very opinionated

Slide 15

Slide 15 text

function add(a, b) { 
 return a + b; 
 } 
 
 
 add(2, 1); // 3 
 
 Function name add a b = a + b 
 
 
 add 2 1 -- 3 
 
 Arguments JS Elm Implicit return add : Int -> Int -> Int Return type

Slide 16

Slide 16 text

import Html exposing (text) 
 
 main = text "Hello world" 
 
 Hello world

Slide 17

Slide 17 text

Virtual DOM elm-html

Slide 18

Slide 18 text

headerView task = 
 header 
 [ class "header" ] 
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 


Slide 19

Slide 19 text

headerView task = 
 header 
 [ class "header" ] 
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 


Slide 20

Slide 20 text

headerView task = 
 header 
 [ class "header" ] 
 [ h1 [] [ text "todos" ] 
 , input 
 [ class "new-todo" 
 , placeholder "What needs to be done?" 
 , autofocus True 
 , value task 
 , name "newTodo" 
 , onInput UpdateField 
 , onEnter Add 
 ] 
 [] 
 ] 
 


Slide 21

Slide 21 text

All functions are stateless

Slide 22

Slide 22 text

function add(a, b) { return a + b; 
 } Side-effects

Slide 23

Slide 23 text

function add(a, b) { 
 window.add = undefined; 
 return a + b; 
 } Side-effects add(2, 1); // 3 add(2, 1);

Slide 24

Slide 24 text

Uncaught TypeError: undefined is not a function

Slide 25

Slide 25 text

No runtime exceptions!

Slide 26

Slide 26 text

Elm is all about guarantees

Slide 27

Slide 27 text

All data is immutable

Slide 28

Slide 28 text

point = { x = 3, y = 4 } 
 
 
 updatePoint point = 
 { point | x = 5 } -- { x = 5, y = 4 } 
 
 Record type

Slide 29

Slide 29 text

Static typing Strong type system Type inference (you don’t have to explicitly write your types)

Slide 30

Slide 30 text

point = { x = 3, y = 4 } 
 
 
 updatePoint point = 
 { point | x = 5 } -- { x = 5, y = 4 } 
 


Slide 31

Slide 31 text

point : { x : Int, y : Int } point = { x = 3, y = 4 } 
 
 
 updatePoint : { x : Int, y : Int } -> { x : Int, y : Int } 
 updatePoint point = 
 { point | x = 5 } Type signature for a point

Slide 32

Slide 32 text

updatePoint : { x : Int, y : Int } -> { x : Int, y : Int } 
 updatePoint point = 
 { point | x = 5 } updatePoint : Point -> Point 
 updatePoint point = 
 { point | x = 5 } 
 
 
 point : { x : Int, y : Int } point = { x = 3, y = 4 } 
 
 
 type alias Point = 
 { x : Int, y : Int } point : Point point = { x = 3, y = 4 } 


Slide 33

Slide 33 text

The compiler will guide you

Slide 34

Slide 34 text

Friendly error messages

Slide 35

Slide 35 text

listView tasks = 
 ul [] (List.nap taskView tasks) 
 
 
 
 taskView task = 
 li [] [ text task.name ] 


Slide 36

Slide 36 text

-- NAMING ERROR ------------------------------------------------------ error.elm Cannot find variable `List.nap`. 17| ul [] (List.nap taskView tasks) ^^^^^^^^ `List` does not expose `nap`. Maybe you want one of the following? List.map List.any List.map2 List.map3

Slide 37

Slide 37 text


 
 main = 
 listView [ { name = 0 } ] listView tasks = 
 ul [] (List.map taskView tasks) 
 
 
 
 taskView task = 
 li [] [ text task.name ] 


Slide 38

Slide 38 text

-- TYPE MISMATCH ----------------------------------------------------- error.elm The argument to function `listView` is causing a mismatch. 20| listView [ { name = 0 } ] ^^^^^^^^^^^^^^^^ Function `listView` is expecting the argument to be: List { name : String } But it is: List { name : number } Hint: Problem in the `name` field. I always figure out field types in alphabetical order. If a field seems fine, I assume it is "correct" in subsequent checks. So the problem may actually be a weird interaction with previous fields.

Slide 39

Slide 39 text

No concept of null

Slide 40

Slide 40 text

type CompassPoint 
 = North 
 | South 
 | East 
 | West 
 
 Union types type User 
 = Anonymous 
 | Named String 


Slide 41

Slide 41 text

type Maybe a 
 = Just a 
 | Nothing 
 
 Generic type Maybe

Slide 42

Slide 42 text

type alias Task = 
 { name : String 
 , description : Maybe String 
 } 
 
 Can either have an description or nothing descriptionView : Task -> String 
 descriptionView task = 
 case task.description of 
 Just description -> 
 description

Slide 43

Slide 43 text

-- MISSING PATTERNS -------------------------------------------------- error.elm This `case` does not have branches for all possibilities. 12|> case task.description of 13|> Just description -> 14|> description You need to account for the following values: Maybe.Nothing Add a branch to cover this pattern!

Slide 44

Slide 44 text

type alias Task = 
 { name : String 
 , description : Maybe String 
 } 
 
 descriptionView : Task -> String 
 descriptionView task = 
 case task.description of 
 Just description -> 
 description 
 Nothing -> 
 “No description” 


Slide 45

Slide 45 text

Refactor with confidence

Slide 46

Slide 46 text

A great package manager

Slide 47

Slide 47 text

The Elm Architecture model-view-update

Slide 48

Slide 48 text

Model Update View Message + state = new state Application state View for current state Message

Slide 49

Slide 49 text

type alias Model = 
 { count : Int 
 } 
 type Msg 
 = Increment 
 | Decrement update : Msg -> Model -> Model 
 update msg model = 
 case msg of 
 Increment -> 
 { model | count = model.count + 1 } 
 
 Decrement -> 
 { model | count = model.count - 1 } view : Model -> Html Msg 
 view model = 
 div [ class "counter" ] 
 [ button [ onClick Decrement ] [ text "-" ] 
 , text (toString model.count) 
 , button [ onClick Increment ] [ text "+" ] 
 ] 


Slide 50

Slide 50 text

Model Update View Model Update View Model Update View

Slide 51

Slide 51 text

What can we learn from Elm?

Slide 52

Slide 52 text

flowtype.org typescriptlang.org Enable strict null checks

Slide 53

Slide 53 text

type AddTodo = { type: "ADD_TODO", id: number, title: string }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TOOD": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } type Action = AddTodo | ToggleTodo; 
 Typo Typed Redux

Slide 54

Slide 54 text

ERROR in ./stores/todos.ts (12,12): error TS2678: Type '"ADD_TOOD"' is not comparable to type '"ADD_TODO" | "TOGGLE_TODO"'.

Slide 55

Slide 55 text

type AddTodo = { type: "ADD_TODO", id: number, title: string }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; 
 
 type Action = AddTodo | ToggleTodo; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 
 Typed Redux

Slide 56

Slide 56 text

type AddTodo = { type: "ADD_TODO", id: number, title: string }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; type ShowCompleted = { type: "SHOW_COMPLETED" }; 
 type Action = AddTodo | ToggleTodo; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 Typed Redux

Slide 57

Slide 57 text

type AddTodo = { type: "ADD_TODO", id: number, title: string }; 
 type ToggleTodo = { type: "TOGGLE_TODO", id: number }; type ShowCompleted = { type: “SHOW_COMPLETED" }; 
 type Action = AddTodo | ToggleTodo | ShowCompleted; 
 
 function todos(state: State, action: Action): State { 
 switch (action.type) { 
 case "ADD_TODO": 
 ... 
 case "TOGGLE_TODO": 
 ... 
 } 
 } 
 Typed Redux

Slide 58

Slide 58 text

ERROR in ./stores/todos.ts (11,61): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

Slide 59

Slide 59 text

-- MISSING PATTERNS -------------------------------------------------- error.elm This `case` does not have branches for all possibilities. 16|> case msg of 17|> AddTodo -> 18|> model 19|> 20|> ToggleTodo -> 21|> model You need to account for the following values: Main.ShowCompleted Add a branch to cover this pattern!

Slide 60

Slide 60 text

Want to learn more? elm-lang.org/ github.com/eggsdesign/elm-meetup

Slide 61

Slide 61 text

meetup.com/oslo-elm-meetup/

Slide 62

Slide 62 text

Thank you! @rechsteiner