Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Scenic City Summit 2017: Tame the frontend with...
Search
Jeremy Fairbank
July 28, 2017
Programming
210
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Scenic City Summit 2017: Tame the frontend with Elm
Jeremy Fairbank
July 28, 2017
More Decks by Jeremy Fairbank
See All by Jeremy Fairbank
Connect.Tech 2020: Advanced Cypress Testing
jfairbank
1
260
CodeMash 2020: Solving the Boolean Identity Crisis
jfairbank
1
220
CodeMash 2020: Practical Functional Programming
jfairbank
1
370
Connect.Tech 2019: Practical Functional Programming
jfairbank
0
440
Connect.Tech 2019: Solving the Boolean Identity Crisis
jfairbank
0
250
Lambda Squared 2019: Solving the Boolean Identity Crisis
jfairbank
0
190
All Things Open 2018: Practical Functional Programming
jfairbank
2
290
Connect.Tech 2018: Effective React Testing
jfairbank
1
220
Fluent Conf 2018: Building web apps with Elm Tutorial
jfairbank
2
930
Other Decks in Programming
See All in Programming
高専、大学編入、そして未踏へ〜プロダクト開発とキャリアの歩み - Technical College, University Transfer, and On to “Mitou” / My Journey in Product Development and Career
pkmiya
0
120
Hono + Inertia + React で LP を構築した話
oukayuka
2
190
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
500
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
4
2.4k
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
590
KotlinConf Extended South Korea 2026 Keynote
l2hyunwoo
0
130
in-process GraphQL のすすめ #ginzajs
izumin5210
4
1.5k
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
400
[PyCon KR 2026] More Variants, More Diversity for AI Accelerators
achimnol
0
130
My Marp Sample
sinoue0108
0
140
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
460
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
250
Featured
See All Featured
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
460
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
320
Git: the NoSQL Database
bkeepers
PRO
432
67k
KATA
mclloyd
PRO
35
15k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Faster Mobile Websites
deanohume
310
32k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.8k
The Pragmatic Product Professional
lauravandoore
37
7.4k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Transcript
Tame the frontend with Elm Jeremy Fairbank @elpapapollo / jfairbank
Tame the frontend with Elm Jeremy Fairbank @elpapapollo / jfairbank
Software is broken. We are here to fix it. Say
[email protected]
Happiness
None
✓ Easier to write code ✓ Easier to write tests
✓ Easier to refactor
elm
No runtime exceptions in practice.
No undefined is not a function
Fast
One framework. No fatigue. Update View Model Messages
elm
Functional
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit Single Expression
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
greet name = "Hello, " ++ name greet "Scenic City
Summit" -- Hello, Scenic City Summit
Pure Data in Data out
Pure No side effects
Pure Predictable and Testable!
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
add x y = x + y add 2 3
== 5 add 2 3 == 5 add 2 3 == 5
Expressive Terse and declarative code
function doubleNumbers(numbers) { const doubled = []; const l =
numbers.length; for (let i = 0; i < l; i++) { doubled.push(numbers[i] * 2); } return doubled; } doubleNumbers([1, 2, 3, 4, 5]); // [2, 4, 6, 8, 10] Imperative
function doubleNumbers(numbers) { const doubled = []; const l =
numbers.length; for (let i = 0; i < l; i++) { doubled.push(numbers[i] * 2); } return doubled; } doubleNumbers([1, 2, 3, 4, 5]); // [2, 4, 6, 8, 10] Imperative ×
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
myList = [1, 2, 3, 4, 5] double n =
n * 2 doubleNumbers list = List.map double list doubleNumbers myList -- [2, 4, 6, 8, 10]
Curried Functions Building blocks
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3
add x y = x + y add 1 2
-- 3 (add 1) 2 -- 3 New function created
increment = add 1 increment 2 -- 3 increment 41
-- 42
increment = add 1 increment 2 -- 3 increment 41
-- 42
increment = add 1 increment 2 -- 3 increment 41
-- 42
Pipes Compose functions with expressive chaining
greet name = "Hello, " ++ name exclaim phrase =
phrase ++ "!" excitedGreeting name = exclaim (greet (String.toUpper name))
greet name = "Hello, " ++ name exclaim phrase =
phrase ++ "!" excitedGreeting name = exclaim (greet (String.toUpper name))
excitedGreeting name = name |> String.toUpper |> greet |> exclaim
excitedGreeting "Tucker"
excitedGreeting name = name |> String.toUpper |> greet |> exclaim
excitedGreeting "Tucker"
"Tucker" |> String.toUpper |> greet |> exclaim
|> String.toUpper "Tucker" |> greet |> exclaim
"TUCKER" |> greet |> exclaim
|> greet "TUCKER" |> exclaim
"Hello, TUCKER" |> exclaim
|> exclaim "Hello, TUCKER"
"Hello, TUCKER!"
No Runtime Exceptions
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
Strong Static Types life : Int life = 42 greeting
: String greeting = "Hello World" isTrue : Bool isTrue = True numbers : List Int numbers = [1, 2, 3]
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> Int -> Int add x y = x + y
greet : String -> String greet name = "Hello, "
++ name add : Int -> (Int -> Int) add x y = x + y
The 2nd argument to function `add` is causing a mismatch.
7| add 2 "3" ^^^ Function `add` is expecting the 2nd argument to be: Int But it is: String Compile time static type checks
Immutable Data Safe and Consistent
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
dog : { name : String, age : Int }
dog = { name = "Tucker" , age = 11 } dog.name -- "Tucker" dog.age -- 11 Records
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
haveBirthday dog = { dog | age = dog.age +
1 } dog = { name = "Tucker", age = 11 } olderDog = haveBirthday dog olderDog.age -- 12 olderDog.name -- "Tucker" dog.age -- 11 dog.name -- "Tucker" Create New Data
Custom Types Domain-specific code
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle
type alias Dog = { name : String , age
: Int , breed : Breed } type Breed = Sheltie | Poodle Union Type
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Sheltie }
dog : Dog dog = { name = "Tucker" ,
age = 11 , breed = Shelty } Misspelled. Won’t compile!
No null or undefined
type Maybe a = Just a | Nothing
type Maybe a = Just a | Nothing Wraps the
successful value
type Maybe a = Just a | Nothing Wraps the
successful value Type Variable
type Maybe a = Just a | Nothing Represents no
result or missing value
type Maybe a = Just a | Nothing Either I
have Just the value a, or I have Nothing.
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
divide : Float -> Float -> Maybe Float divide x
y = if y == 0 then Nothing else Just (x / y) divide 4 2 -- Just 2 divide 4 0 -- Nothing
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) Nothing -> "No Result"
case divide 4 2 of Just n -> "Result is
" ++ (toString n) -- Nothing -> -- "No Result"
Exhaustive matching This `case` does not have branches for all
possibilities. 21|> case divide 4 2 of 22|> Just n -> 23|> "Result is " ++ (toString n) You need to account for the following values: Maybe.Nothing Add a branch to cover this pattern!
Update View Model Messages The Elm Architecture
model Update View
model Update View VDOM
model Update View
model Update View
model Update View
model Update View
model Update View
model Update View VDOM
Demos The Elm Architecture in Action
Getting Started • elm-lang.org • elm-lang.org/examples • guide.elm-lang.org • www.elm-tutorial.org
• builtwithelm.co • Slack • elmlang.herokuapp.com
Thanks! Jeremy Fairbank @elpapapollo / jfairbank Slides: bit.ly/scs-elm