Some FP JS & Ramda
web :: rwp.im
github :: rpearce
email :: me@robertwpearce.com
tweeter :: @RobertWPearce
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 1
about me
Hi, I'm Robert
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
• Work at Articulate (articulate.com / rise.com)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
• Work at Articulate (articulate.com / rise.com)
• Work with FP in JS all day
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
• Work at Articulate (articulate.com / rise.com)
• Work with FP in JS all day
• Writing the Ramda Guide (ramda.guide)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
• Work at Articulate (articulate.com / rise.com)
• Work with FP in JS all day
• Writing the Ramda Guide (ramda.guide)
• Enjoy Rust (
!
) & Haskell (λ)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
about me
Hi, I'm Robert
• Started out at Jack Russell Software w/ Tom Wilson in 2011
• Work at Articulate (articulate.com / rise.com)
• Work with FP in JS all day
• Writing the Ramda Guide (ramda.guide)
• Enjoy Rust (
!
) & Haskell (λ)
• Am a dad
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
Question:
what are we going to do?
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 3
Answer:
three things
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
Answer:
three things
1. look at some foundational FP in JS slides
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
Answer:
three things
1. look at some foundational FP in JS slides
2. refactor a function that updates something deep in an object
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
Answer:
three things
1. look at some foundational FP in JS slides
2. refactor a function that updates something deep in an object
3. dive deep into rain, the UK, olympic pools, and furry creatures
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
!
buckle up
let's do some basics
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 5
!
Pass functions as values
const handleClick = e => {
console.log('click event: ', e)
}
document.addEventListener('click', handleClick)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
!
Pass functions as values
const handleClick = e => {
console.log('click event: ', e)
}
document.addEventListener('click', handleClick)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
!
Pass functions as values
const handleClick = e => {
console.log('click event: ', e)
}
document.addEventListener('click', handleClick)
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = (a, b) => b + a
const add2 = add.bind(null, 2)
add2(3) // 5
add2(5) // 7
const add = a => b => b + a
const add3 = add(3)
add3(2) // 5
add3(4) // 7
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
currying
!
and partial application
const add = a => b => b + a
// is equivalent to
function add(a) {
return function(b) {
return b + a
}
}
// but...
add(2)(3) // 5
add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
!
Composition
const add = a => b => b + a
const add2 = add(2)
const sub = a => b => b - a
const sub1 = sub(1)
const mult = a => b => b * a
const mult10 = mult(10)
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
!
Composition
const add = a => b => b + a
const add2 = add(2)
const sub = a => b => b - a
const sub1 = sub(1)
const mult = a => b => b * a
const mult10 = mult(10)
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
!
Composition
const add = a => b => b + a
const add2 = add(2)
const sub = a => b => b - a
const sub1 = sub(1)
const mult = a => b => b * a
const mult10 = mult(10)
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
!
Composition
const add = a => b => b + a
const add2 = add(2)
const sub = a => b => b - a
const sub1 = sub(1)
const mult = a => b => b * a
const mult10 = mult(10)
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
!
Composition
const add = a => b => b + a
const add2 = add(2)
const sub = a => b => b - a
const sub1 = sub(1)
const mult = a => b => b * a
const mult10 = mult(10)
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
!
map
const films = [
{ title: 'The Empire Strikes Back', rating: 8.8 },
{ title: 'Pulp Fiction', rating: 8.9 },
{ title: 'The Deer Hunter', rating: 8.2 },
{ title: 'The Lion King', rating: 8.5 }
]
// filmHtml :: Film -> Html
const filmHtml = film =>
`<div>${film.title}, <strong>${film.rating}</strong></div>`
films.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// "<div>The Deer Hunter, <strong>8.2</strong></div>",
// "<div>The Lion King, <strong>8.5</strong></div>"
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
!
map
const films = [
{ title: 'The Empire Strikes Back', rating: 8.8 },
{ title: 'Pulp Fiction', rating: 8.9 },
{ title: 'The Deer Hunter', rating: 8.2 },
{ title: 'The Lion King', rating: 8.5 }
]
// filmHtml :: Film -> Html
const filmHtml = film =>
`<div>${film.title}, <strong>${film.rating}</strong></div>`
films.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// "<div>The Deer Hunter, <strong>8.2</strong></div>",
// "<div>The Lion King, <strong>8.5</strong></div>"
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
!
map
const films = [
{ title: 'The Empire Strikes Back', rating: 8.8 },
{ title: 'Pulp Fiction', rating: 8.9 },
{ title: 'The Deer Hunter', rating: 8.2 },
{ title: 'The Lion King', rating: 8.5 }
]
// filmHtml :: Film -> Html
const filmHtml = film =>
`<div>${film.title}, <strong>${film.rating}</strong></div>`
films.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// "<div>The Deer Hunter, <strong>8.2</strong></div>",
// "<div>The Lion King, <strong>8.5</strong></div>"
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
!
map
const films = [
{ title: 'The Empire Strikes Back', rating: 8.8 },
{ title: 'Pulp Fiction', rating: 8.9 },
{ title: 'The Deer Hunter', rating: 8.2 },
{ title: 'The Lion King', rating: 8.5 }
]
// filmHtml :: Film -> Html
const filmHtml = film =>
`<div>${film.title}, <strong>${film.rating}</strong></div>`
films.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// "<div>The Deer Hunter, <strong>8.2</strong></div>",
// "<div>The Lion King, <strong>8.5</strong></div>"
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
!
map
const films = [
{ title: 'The Empire Strikes Back', rating: 8.8 },
{ title: 'Pulp Fiction', rating: 8.9 },
{ title: 'The Deer Hunter', rating: 8.2 },
{ title: 'The Lion King', rating: 8.5 }
]
// filmHtml :: Film -> Html
const filmHtml = film =>
`<div>${film.title}, <strong>${film.rating}</strong></div>`
films.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// "<div>The Deer Hunter, <strong>8.2</strong></div>",
// "<div>The Lion King, <strong>8.5</strong></div>"
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
!
filter
const films = // ...
// hasHighScore :: Film -> Bool
const hasHighScore = film =>
film.rating >= 8.8
films
.filter(hasHighScore)
.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
!
filter
const films = // ...
// hasHighScore :: Film -> Bool
const hasHighScore = film =>
film.rating >= 8.8
films
.filter(hasHighScore)
.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
!
filter
const films = // ...
// hasHighScore :: Film -> Bool
const hasHighScore = film =>
film.rating >= 8.8
films
.filter(hasHighScore)
.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
!
filter
const films = // ...
// hasHighScore :: Film -> Bool
const hasHighScore = film =>
film.rating >= 8.8
films
.filter(hasHighScore)
.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
!
filter
const films = // ...
// hasHighScore :: Film -> Bool
const hasHighScore = film =>
film.rating >= 8.8
films
.filter(hasHighScore)
.map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
!
reduce (fold)
const films = // ...
// highScoresHtml :: ([Html], Film) -> [Html]
const highScoresHtml = (acc, film) =>
hasHighScore(film)
? acc.concat(filmHtml(film))
: acc
films.reduce(highScoresHtml, [])
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
!
reduce (fold)
const films = // ...
// highScoresHtml :: ([Html], Film) -> [Html]
const highScoresHtml = (acc, film) =>
hasHighScore(film)
? acc.concat(filmHtml(film))
: acc
films.reduce(highScoresHtml, [])
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
!
reduce (fold)
const films = // ...
// highScoresHtml :: ([Html], Film) -> [Html]
const highScoresHtml = (acc, film) =>
hasHighScore(film)
? acc.concat(filmHtml(film))
: acc
films.reduce(highScoresHtml, [])
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
"Practical, functional JavaScript."
— ramdajs.com
@RobertWPearce • Photo by Kirill Zakharov on Unsplash 13
!
ramda
@RobertWPearce • Photo by George Hiles on Unsplash 14
!
ramda
• easier to create functional pipelines
@RobertWPearce • Photo by George Hiles on Unsplash 14
!
ramda
• easier to create functional pipelines
• immutability
@RobertWPearce • Photo by George Hiles on Unsplash 14
!
ramda
• easier to create functional pipelines
• immutability
• side-effect free code
@RobertWPearce • Photo by George Hiles on Unsplash 14
!
ramda
• easier to create functional pipelines
• immutability
• side-effect free code
• all functions curried
@RobertWPearce • Photo by George Hiles on Unsplash 14
!
ramda
• easier to create functional pipelines
• immutability
• side-effect free code
• all functions curried
• provide data last
@RobertWPearce • Photo by George Hiles on Unsplash 14
refactor with ramda
mult10(sub1(add2(9))) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 15
refactor with ramda
// mult10(sub1(add2(9))) // 100
import { compose } from 'ramda'
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 16
refactor with ramda
// mult10(sub1(add2(9))) // 100
import { compose } from 'ramda'
compose(mult10, sub1, add2)(9) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 17
refactor with ramda
// mult10(sub1(add2(9))) // 100
import { compose } from 'ramda'
// compose(mult10, sub1, add2)(9) // 100
const doMaths =
compose(mult10, sub1, add2)
doMaths(9) // 100
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 18
refactor with ramda #2
films.filter(hasHighScore).map(filmHtml)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 19
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 20
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
compose(map(filmHtml), filter(hasHighScore))
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 21
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
// output :: [Film] -> [Html]
const output =
compose(map(filmHtml), filter(hasHighScore))
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 22
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
// output :: [Film] -> [Html]
const output =
compose(map(filmHtml), filter(hasHighScore))
output(films)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 23
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
// output :: [Film] -> [Html]
const output =
compose(map(filmHtml), filter(hasHighScore))
output(films)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 23
refactor with ramda #2
// films.filter(hasHighScore).map(filmHtml)
import { compose, filter, map } from 'ramda'
// filmsToHtml :: [Film] -> [Html]
const filmsToHtml =
map(filmHtml)
// highScores :: [Film] -> [Film]
const highScores =
filter(hasHighScore)
// output :: [Film] -> [Html]
const output =
compose(filmsToHtml, highScores)
output(films)
// => [
// "<div>The Empire Strikes Back, <strong>8.8</strong></div>",
// "<div>Pulp Fiction, <strong>8.9</strong></div>",
// ]
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 24
(demos)
ramda repl refactor!
https://github.com/rpearce/talk-ramda-
rainfall
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 25
!
ramda example: converting method APIs
document.querySelectorAll('div').length // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 26
!
ramda example: converting method APIs
import { compose, invoker, length } from 'ramda'
const querySelectorAll =
invoker(1, 'querySelectorAll')
const countDivs =
compose(length, querySelectorAll('div'))
countDivs(document) // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
!
ramda example: converting method APIs
import { compose, invoker, length } from 'ramda'
const querySelectorAll =
invoker(1, 'querySelectorAll')
const countDivs =
compose(length, querySelectorAll('div'))
countDivs(document) // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
!
ramda example: converting method APIs
import { compose, invoker, length } from 'ramda'
const querySelectorAll =
invoker(1, 'querySelectorAll')
const countDivs =
compose(length, querySelectorAll('div'))
countDivs(document) // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
!
ramda example: converting method APIs
import { compose, invoker, length } from 'ramda'
const querySelectorAll =
invoker(1, 'querySelectorAll')
const countDivs =
compose(length, querySelectorAll('div'))
countDivs(document) // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
!
ramda example: converting method APIs
import { compose, invoker, length } from 'ramda'
const querySelectorAll =
invoker(1, 'querySelectorAll')
const countDivs =
compose(length, querySelectorAll('div'))
countDivs(document) // 76
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
where can i learn more?
• ramdajs.com
• egghead.io ramda course
• Professor Frisby's Mostly Adequate Guide to Functional
Programming
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 28
where can i learn more?
ramda.guide
rwp.im
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 29
Some FP JS & Ramda
web :: rwp.im
github :: rpearce
email :: me@robertwpearce.com
tweeter :: @RobertWPearce
@RobertWPearce | rwp.im | 2022-01-20 charleston.js 30

Some Functional Programming in JavaScript and Ramda.js

  • 1.
    Some FP JS& Ramda web :: rwp.im github :: rpearce email :: me@robertwpearce.com tweeter :: @RobertWPearce @RobertWPearce | rwp.im | 2022-01-20 charleston.js 1
  • 2.
    about me Hi, I'mRobert @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 3.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 4.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 • Work at Articulate (articulate.com / rise.com) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 5.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 • Work at Articulate (articulate.com / rise.com) • Work with FP in JS all day @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 6.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 • Work at Articulate (articulate.com / rise.com) • Work with FP in JS all day • Writing the Ramda Guide (ramda.guide) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 7.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 • Work at Articulate (articulate.com / rise.com) • Work with FP in JS all day • Writing the Ramda Guide (ramda.guide) • Enjoy Rust ( ! ) & Haskell (λ) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 8.
    about me Hi, I'mRobert • Started out at Jack Russell Software w/ Tom Wilson in 2011 • Work at Articulate (articulate.com / rise.com) • Work with FP in JS all day • Writing the Ramda Guide (ramda.guide) • Enjoy Rust ( ! ) & Haskell (λ) • Am a dad @RobertWPearce | rwp.im | 2022-01-20 charleston.js 2
  • 9.
    Question: what are wegoing to do? @RobertWPearce | rwp.im | 2022-01-20 charleston.js 3
  • 10.
    Answer: three things @RobertWPearce |rwp.im | 2022-01-20 charleston.js 4
  • 11.
    Answer: three things 1. lookat some foundational FP in JS slides @RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
  • 12.
    Answer: three things 1. lookat some foundational FP in JS slides 2. refactor a function that updates something deep in an object @RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
  • 13.
    Answer: three things 1. lookat some foundational FP in JS slides 2. refactor a function that updates something deep in an object 3. dive deep into rain, the UK, olympic pools, and furry creatures @RobertWPearce | rwp.im | 2022-01-20 charleston.js 4
  • 14.
    ! buckle up let's dosome basics @RobertWPearce | rwp.im | 2022-01-20 charleston.js 5
  • 15.
    ! Pass functions asvalues const handleClick = e => { console.log('click event: ', e) } document.addEventListener('click', handleClick) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
  • 16.
    ! Pass functions asvalues const handleClick = e => { console.log('click event: ', e) } document.addEventListener('click', handleClick) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
  • 17.
    ! Pass functions asvalues const handleClick = e => { console.log('click event: ', e) } document.addEventListener('click', handleClick) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 6
  • 18.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 19.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 20.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 21.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 22.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 23.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 24.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 25.
    currying ! and partial application constadd = (a, b) => b + a const add2 = add.bind(null, 2) add2(3) // 5 add2(5) // 7 const add = a => b => b + a const add3 = add(3) add3(2) // 5 add3(4) // 7 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 7
  • 26.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 27.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 28.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 29.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 30.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 31.
    currying ! and partial application constadd = a => b => b + a // is equivalent to function add(a) { return function(b) { return b + a } } // but... add(2)(3) // 5 add(2, 3) // function add() ... (╯°□°)╯︵ ┻━┻ @RobertWPearce | rwp.im | 2022-01-20 charleston.js 8
  • 32.
    ! Composition const add =a => b => b + a const add2 = add(2) const sub = a => b => b - a const sub1 = sub(1) const mult = a => b => b * a const mult10 = mult(10) mult10(sub1(add2(9))) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
  • 33.
    ! Composition const add =a => b => b + a const add2 = add(2) const sub = a => b => b - a const sub1 = sub(1) const mult = a => b => b * a const mult10 = mult(10) mult10(sub1(add2(9))) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
  • 34.
    ! Composition const add =a => b => b + a const add2 = add(2) const sub = a => b => b - a const sub1 = sub(1) const mult = a => b => b * a const mult10 = mult(10) mult10(sub1(add2(9))) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
  • 35.
    ! Composition const add =a => b => b + a const add2 = add(2) const sub = a => b => b - a const sub1 = sub(1) const mult = a => b => b * a const mult10 = mult(10) mult10(sub1(add2(9))) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
  • 36.
    ! Composition const add =a => b => b + a const add2 = add(2) const sub = a => b => b - a const sub1 = sub(1) const mult = a => b => b * a const mult10 = mult(10) mult10(sub1(add2(9))) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 9
  • 37.
    ! map const films =[ { title: 'The Empire Strikes Back', rating: 8.8 }, { title: 'Pulp Fiction', rating: 8.9 }, { title: 'The Deer Hunter', rating: 8.2 }, { title: 'The Lion King', rating: 8.5 } ] // filmHtml :: Film -> Html const filmHtml = film => `<div>${film.title}, <strong>${film.rating}</strong></div>` films.map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // "<div>The Deer Hunter, <strong>8.2</strong></div>", // "<div>The Lion King, <strong>8.5</strong></div>" // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
  • 38.
    ! map const films =[ { title: 'The Empire Strikes Back', rating: 8.8 }, { title: 'Pulp Fiction', rating: 8.9 }, { title: 'The Deer Hunter', rating: 8.2 }, { title: 'The Lion King', rating: 8.5 } ] // filmHtml :: Film -> Html const filmHtml = film => `<div>${film.title}, <strong>${film.rating}</strong></div>` films.map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // "<div>The Deer Hunter, <strong>8.2</strong></div>", // "<div>The Lion King, <strong>8.5</strong></div>" // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
  • 39.
    ! map const films =[ { title: 'The Empire Strikes Back', rating: 8.8 }, { title: 'Pulp Fiction', rating: 8.9 }, { title: 'The Deer Hunter', rating: 8.2 }, { title: 'The Lion King', rating: 8.5 } ] // filmHtml :: Film -> Html const filmHtml = film => `<div>${film.title}, <strong>${film.rating}</strong></div>` films.map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // "<div>The Deer Hunter, <strong>8.2</strong></div>", // "<div>The Lion King, <strong>8.5</strong></div>" // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
  • 40.
    ! map const films =[ { title: 'The Empire Strikes Back', rating: 8.8 }, { title: 'Pulp Fiction', rating: 8.9 }, { title: 'The Deer Hunter', rating: 8.2 }, { title: 'The Lion King', rating: 8.5 } ] // filmHtml :: Film -> Html const filmHtml = film => `<div>${film.title}, <strong>${film.rating}</strong></div>` films.map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // "<div>The Deer Hunter, <strong>8.2</strong></div>", // "<div>The Lion King, <strong>8.5</strong></div>" // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
  • 41.
    ! map const films =[ { title: 'The Empire Strikes Back', rating: 8.8 }, { title: 'Pulp Fiction', rating: 8.9 }, { title: 'The Deer Hunter', rating: 8.2 }, { title: 'The Lion King', rating: 8.5 } ] // filmHtml :: Film -> Html const filmHtml = film => `<div>${film.title}, <strong>${film.rating}</strong></div>` films.map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // "<div>The Deer Hunter, <strong>8.2</strong></div>", // "<div>The Lion King, <strong>8.5</strong></div>" // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 10
  • 42.
    ! filter const films =// ... // hasHighScore :: Film -> Bool const hasHighScore = film => film.rating >= 8.8 films .filter(hasHighScore) .map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
  • 43.
    ! filter const films =// ... // hasHighScore :: Film -> Bool const hasHighScore = film => film.rating >= 8.8 films .filter(hasHighScore) .map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
  • 44.
    ! filter const films =// ... // hasHighScore :: Film -> Bool const hasHighScore = film => film.rating >= 8.8 films .filter(hasHighScore) .map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
  • 45.
    ! filter const films =// ... // hasHighScore :: Film -> Bool const hasHighScore = film => film.rating >= 8.8 films .filter(hasHighScore) .map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
  • 46.
    ! filter const films =// ... // hasHighScore :: Film -> Bool const hasHighScore = film => film.rating >= 8.8 films .filter(hasHighScore) .map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 11
  • 47.
    ! reduce (fold) const films= // ... // highScoresHtml :: ([Html], Film) -> [Html] const highScoresHtml = (acc, film) => hasHighScore(film) ? acc.concat(filmHtml(film)) : acc films.reduce(highScoresHtml, []) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
  • 48.
    ! reduce (fold) const films= // ... // highScoresHtml :: ([Html], Film) -> [Html] const highScoresHtml = (acc, film) => hasHighScore(film) ? acc.concat(filmHtml(film)) : acc films.reduce(highScoresHtml, []) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
  • 49.
    ! reduce (fold) const films= // ... // highScoresHtml :: ([Html], Film) -> [Html] const highScoresHtml = (acc, film) => hasHighScore(film) ? acc.concat(filmHtml(film)) : acc films.reduce(highScoresHtml, []) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 12
  • 50.
    "Practical, functional JavaScript." —ramdajs.com @RobertWPearce • Photo by Kirill Zakharov on Unsplash 13
  • 51.
    ! ramda @RobertWPearce • Photoby George Hiles on Unsplash 14
  • 52.
    ! ramda • easier tocreate functional pipelines @RobertWPearce • Photo by George Hiles on Unsplash 14
  • 53.
    ! ramda • easier tocreate functional pipelines • immutability @RobertWPearce • Photo by George Hiles on Unsplash 14
  • 54.
    ! ramda • easier tocreate functional pipelines • immutability • side-effect free code @RobertWPearce • Photo by George Hiles on Unsplash 14
  • 55.
    ! ramda • easier tocreate functional pipelines • immutability • side-effect free code • all functions curried @RobertWPearce • Photo by George Hiles on Unsplash 14
  • 56.
    ! ramda • easier tocreate functional pipelines • immutability • side-effect free code • all functions curried • provide data last @RobertWPearce • Photo by George Hiles on Unsplash 14
  • 57.
    refactor with ramda mult10(sub1(add2(9)))// 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 15
  • 58.
    refactor with ramda //mult10(sub1(add2(9))) // 100 import { compose } from 'ramda' @RobertWPearce | rwp.im | 2022-01-20 charleston.js 16
  • 59.
    refactor with ramda //mult10(sub1(add2(9))) // 100 import { compose } from 'ramda' compose(mult10, sub1, add2)(9) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 17
  • 60.
    refactor with ramda //mult10(sub1(add2(9))) // 100 import { compose } from 'ramda' // compose(mult10, sub1, add2)(9) // 100 const doMaths = compose(mult10, sub1, add2) doMaths(9) // 100 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 18
  • 61.
    refactor with ramda#2 films.filter(hasHighScore).map(filmHtml) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 19
  • 62.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' @RobertWPearce | rwp.im | 2022-01-20 charleston.js 20
  • 63.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' compose(map(filmHtml), filter(hasHighScore)) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 21
  • 64.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' // output :: [Film] -> [Html] const output = compose(map(filmHtml), filter(hasHighScore)) @RobertWPearce | rwp.im | 2022-01-20 charleston.js 22
  • 65.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' // output :: [Film] -> [Html] const output = compose(map(filmHtml), filter(hasHighScore)) output(films) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 23
  • 66.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' // output :: [Film] -> [Html] const output = compose(map(filmHtml), filter(hasHighScore)) output(films) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 23
  • 67.
    refactor with ramda#2 // films.filter(hasHighScore).map(filmHtml) import { compose, filter, map } from 'ramda' // filmsToHtml :: [Film] -> [Html] const filmsToHtml = map(filmHtml) // highScores :: [Film] -> [Film] const highScores = filter(hasHighScore) // output :: [Film] -> [Html] const output = compose(filmsToHtml, highScores) output(films) // => [ // "<div>The Empire Strikes Back, <strong>8.8</strong></div>", // "<div>Pulp Fiction, <strong>8.9</strong></div>", // ] @RobertWPearce | rwp.im | 2022-01-20 charleston.js 24
  • 68.
  • 69.
    ! ramda example: convertingmethod APIs document.querySelectorAll('div').length // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 26
  • 70.
    ! ramda example: convertingmethod APIs import { compose, invoker, length } from 'ramda' const querySelectorAll = invoker(1, 'querySelectorAll') const countDivs = compose(length, querySelectorAll('div')) countDivs(document) // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
  • 71.
    ! ramda example: convertingmethod APIs import { compose, invoker, length } from 'ramda' const querySelectorAll = invoker(1, 'querySelectorAll') const countDivs = compose(length, querySelectorAll('div')) countDivs(document) // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
  • 72.
    ! ramda example: convertingmethod APIs import { compose, invoker, length } from 'ramda' const querySelectorAll = invoker(1, 'querySelectorAll') const countDivs = compose(length, querySelectorAll('div')) countDivs(document) // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
  • 73.
    ! ramda example: convertingmethod APIs import { compose, invoker, length } from 'ramda' const querySelectorAll = invoker(1, 'querySelectorAll') const countDivs = compose(length, querySelectorAll('div')) countDivs(document) // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
  • 74.
    ! ramda example: convertingmethod APIs import { compose, invoker, length } from 'ramda' const querySelectorAll = invoker(1, 'querySelectorAll') const countDivs = compose(length, querySelectorAll('div')) countDivs(document) // 76 @RobertWPearce | rwp.im | 2022-01-20 charleston.js 27
  • 75.
    where can ilearn more? • ramdajs.com • egghead.io ramda course • Professor Frisby's Mostly Adequate Guide to Functional Programming @RobertWPearce | rwp.im | 2022-01-20 charleston.js 28
  • 76.
    where can ilearn more? ramda.guide rwp.im @RobertWPearce | rwp.im | 2022-01-20 charleston.js 29
  • 77.
    Some FP JS& Ramda web :: rwp.im github :: rpearce email :: me@robertwpearce.com tweeter :: @RobertWPearce @RobertWPearce | rwp.im | 2022-01-20 charleston.js 30