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
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