Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lambda Squared 2018: Practical Functional Progr...

Lambda Squared 2018: Practical Functional Programming

Jeremy Fairbank

March 30, 2018
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

  1. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  2. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  3. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  4. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  5. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  6. const td = require('testdouble') describe('order details', () => { let

    originalLog = console.log let printOrderDetails let fetchJson beforeEach(() => { fetchJson = td.replace('./fetchJson') console.log = td.function('console.log') printOrderDetails = require('./printOrderDetails') }) afterEach(() => { td.reset() console.log = originalLog })
  7. const td = require('testdouble') describe('order details', () => { let

    originalLog = console.log let printOrderDetails let fetchJson beforeEach(() => { fetchJson = td.replace('./fetchJson') console.log = td.function('console.log') printOrderDetails = require('./printOrderDetails') }) afterEach(() => { td.reset() console.log = originalLog })
  8. const td = require('testdouble') describe('order details', () => { let

    originalLog = console.log let printOrderDetails let fetchJson beforeEach(() => { fetchJson = td.replace('./fetchJson') console.log = td.function('console.log') printOrderDetails = require('./printOrderDetails') }) afterEach(() => { td.reset() console.log = originalLog })
  9. const td = require('testdouble') describe('order details', () => { let

    originalLog = console.log let printOrderDetails let fetchJson beforeEach(() => { fetchJson = td.replace('./fetchJson') console.log = td.function('console.log') printOrderDetails = require('./printOrderDetails') }) afterEach(() => { td.reset() console.log = originalLog })
  10. it('prints details for multiple orders', async () => { td

    .when(fetchJson('/orders?ids=1,2,3')) .thenResolve([ { id: 1, date: '12/1/17', customer: 'Tucker' }, { id: 2, date: '11/25/17', customer: 'Sally' }, { id: 3, date: '3/30/18', customer: 'Joe' }, ]) await printOrderDetails([1, 2, 3]) td.verify(console.log('Order 1 on 12/1/17 by Tucker')) td.verify(console.log('Order 2 on 11/25/17 by Sally')) td.verify(console.log('Order 3 on 3/30/18 by Joe')) }) })
  11. it('prints details for multiple orders', async () => { td

    .when(fetchJson('/orders?ids=1,2,3')) .thenResolve([ { id: 1, date: '12/1/17', customer: 'Tucker' }, { id: 2, date: '11/25/17', customer: 'Sally' }, { id: 3, date: '3/30/18', customer: 'Joe' }, ]) await printOrderDetails([1, 2, 3]) td.verify(console.log('Order 1 on 12/1/17 by Tucker')) td.verify(console.log('Order 2 on 11/25/17 by Sally')) td.verify(console.log('Order 3 on 3/30/18 by Joe')) }) })
  12. it('prints details for multiple orders', async () => { td

    .when(fetchJson('/orders?ids=1,2,3')) .thenResolve([ { id: 1, date: '12/1/17', customer: 'Tucker' }, { id: 2, date: '11/25/17', customer: 'Sally' }, { id: 3, date: '3/30/18', customer: 'Joe' }, ]) await printOrderDetails([1, 2, 3]) td.verify(console.log('Order 1 on 12/1/17 by Tucker')) td.verify(console.log('Order 2 on 11/25/17 by Sally')) td.verify(console.log('Order 3 on 3/30/18 by Joe')) }) })
  13. it('prints details for multiple orders', async () => { td

    .when(fetchJson('/orders?ids=1,2,3')) .thenResolve([ { id: 1, date: '12/1/17', customer: 'Tucker' }, { id: 2, date: '11/25/17', customer: 'Sally' }, { id: 3, date: '3/30/18', customer: 'Joe' }, ]) await printOrderDetails([1, 2, 3]) td.verify(console.log('Order 1 on 12/1/17 by Tucker')) td.verify(console.log('Order 2 on 11/25/17 by Sally')) td.verify(console.log('Order 3 on 3/30/18 by Joe')) }) })
  14. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  15. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  16. async function printOrderDetails(ids) { let url = `/orders?ids=${ids.join(',')}` let orders

    = await fetchJson(url) for (let i = 0; i < orders.length; i++) { let { id, date, customer } = orders[i] let details = `Order ${id} on ${date} by ${customer}` console.log(details) } }
  17. const add = (x, y) => x + y add(2,

    3) === 5 add(2, 3) === 5 add(2, 3) === 5
  18. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  19. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  20. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  21. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  22. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  23. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  24. const url = ids => `/orders?ids=${ids.join(',')}` const orderDetails = ({

    id, date, customer }) => `Order ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  25. it('creates details for orders', () => { let orders =

    [ { id: 1, date: '12/1/17', customer: 'Tucker' }, { id: 2, date: '11/25/17', customer: 'Sally' }, { id: 3, date: '3/30/18', customer: 'Joe' }, ] expect(detailsForOrders(orders)).toEqual([ 'Order 1 on 12/1/17 by Tucker', 'Order 2 on 11/25/17 by Sally', 'Order 3 on 3/30/18 by Joe', ]) })
  26. async function printOrderDetails(ids) { let orders = await fetchJson(url(ids)) let

    details = detailsForOrders(orders) for (let i = 0; i < details.length; i++) { console.log(details[i]) } }
  27. async function printOrderDetails(ids) { let orders = await fetchJson(url(ids)) let

    details = detailsForOrders(orders) for (let i = 0; i < details.length; i++) { console.log(details[i]) } }
  28. async function printOrderDetails(ids) { let orders = await fetchJson(url(ids)) let

    details = detailsForOrders(orders) for (let i = 0; i < details.length; i++) { console.log(details[i]) } }
  29. async function printOrderDetails(ids) { let orders = await fetchJson(url(ids)) let

    details = detailsForOrders(orders) for (let i = 0; i < details.length; i++) { console.log(details[i]) } }
  30. const orderDetails = ({ id, date, customer }) => `Order

    ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  31. const orderDetails = ({ id, date, customer }) => `Order

    ${id} on ${date} by ${customer}` function detailsForOrders(orders) { let details = [] for (let i = 0; i < orders.length; i++) { details.push(orderDetails(orders[i])) } return details }
  32. const orderDetails = ({ id, date, customer }) => `Order

    ${id} on ${date} by ${customer}` const detailsForOrders = orders => orders.map(orderDetails)
  33. const orderDetails = ({ id, date, customer }) => `Order

    ${id} on ${date} by ${customer}` const detailsForOrders = orders => orders.map(orderDetails)
  34. { id: 1, date: '12/1/17', customer: 'Tucker' } { id:

    2, date: '11/25/17', customer: 'Sally' } { id: 3, date: '3/30/18', customer: 'Joe' }
  35. { id: 1, date: '12/1/17', customer: 'Tucker' } { id:

    2, date: '11/25/17', customer: 'Sally' } { id: 3, date: '3/30/18', customer: 'Joe' } [ 'Order 1 on 12/1/17 by Tucker', ] map orderDetails
  36. [ 'Order 1 on 12/1/17 by Tucker', 'Order 2 on

    11/25/17 by Sally', ] orderDetails { id: 1, date: '12/1/17', customer: 'Tucker' } { id: 2, date: '11/25/17', customer: 'Sally' } { id: 3, date: '3/30/18', customer: 'Joe' } map
  37. orderDetails [ 'Order 1 on 12/1/17 by Tucker', 'Order 2

    on 11/25/17 by Sally', 'Order 3 on 3/30/18 by Joe', ] map { id: 1, date: '12/1/17', customer: 'Tucker' } { id: 2, date: '11/25/17', customer: 'Sally' } { id: 3, date: '3/30/18', customer: 'Joe' }
  38. class Person { constructor(name, hobbies) { this.name = name this.hobbies

    = hobbies } describe() { if (this.hobbies.length === 0) { return `${this.name} doesn't do much` } let hobbies = this.hobbies.splice(0, 2).join(' and ') return `${this.name} likes to do things such as ${hobbies}` } }
  39. class Person { constructor(name, hobbies) { this.name = name this.hobbies

    = hobbies } describe() { if (this.hobbies.length === 0) { return `${this.name} doesn't do much` } let hobbies = this.hobbies.splice(0, 2).join(' and ') return `${this.name} likes to do things such as ${hobbies}` } }
  40. class Person { constructor(name, hobbies) { this.name = name this.hobbies

    = hobbies } describe() { if (this.hobbies.length === 0) { return `${this.name} doesn't do much` } let hobbies = this.hobbies.splice(0, 2).join(' and ') return `${this.name} likes to do things such as ${hobbies}` } }
  41. class Person { constructor(name, hobbies) { this.name = name this.hobbies

    = hobbies } describe() { if (this.hobbies.length === 0) { return `${this.name} doesn't do much` } let hobbies = this.hobbies.splice(0, 2).join(' and ') return `${this.name} likes to do things such as ${hobbies}` } }
  42. let person = new Person('Jeremy', [ 'programming', 'reading', 'playing music',

    ]) person.describe() // Jeremy likes to do things such as programming and reading person.describe() // Jeremy likes to do things such as playing music
  43. let person = new Person('Jeremy', [ 'programming', 'reading', 'playing music',

    ]) person.describe() // Jeremy likes to do things such as programming and reading person.describe() // Jeremy likes to do things such as playing music
  44. let person = new Person('Jeremy', [ 'programming', 'reading', 'playing music',

    ]) person.describe() // Jeremy likes to do things such as programming and reading person.describe() // Jeremy likes to do things such as playing music
  45. let person = new Person('Jeremy', [ 'programming', 'reading', 'playing music',

    ]) person.describe() // Jeremy likes to do things such as programming and reading person.describe() // Jeremy likes to do things such as playing music
  46. class Person { // ... describe() { // ... let

    hobbies = this.hobbies.splice(0, 2).join(' and ') // ... } }
  47. class Person { // ... describe() { // ... let

    hobbies = this.hobbies.splice(0, 2).join(' and ') // ... } } TypeError: Cannot add/remove sealed array elements
  48. class Person { // ... describe() { // ... let

    hobbies = this.hobbies.slice(0, 2).join(' and ') // ... } }
  49. const create = (name, hobbies) => Object.freeze({ name, hobbies: Object.freeze(hobbies)

    }) function describe(person) { if (person.hobbies.length === 0) { return `${person.name} doesn't do much` } let hobbies = person.hobbies.slice(0, 2).join(' and ') return `${person.name} likes to do things such as ${hobbies}` }
  50. const create = (name, hobbies) => Object.freeze({ name, hobbies: Object.freeze(hobbies)

    }) function describe(person) { if (person.hobbies.length === 0) { return `${person.name} doesn't do much` } let hobbies = person.hobbies.slice(0, 2).join(' and ') return `${person.name} likes to do things such as ${hobbies}` }
  51. const create = (name, hobbies) => Object.freeze({ name, hobbies: Object.freeze(hobbies)

    }) function describe(person) { if (person.hobbies.length === 0) { return `${person.name} doesn't do much` } let hobbies = person.hobbies.slice(0, 2).join(' and ') return `${person.name} likes to do things such as ${hobbies}` }
  52. let person = create('Jeremy', []) person = addHobby('programming', person) person

    = addHobby('reading', person) describe(person) // Jeremy likes to do things such as programming and reading
  53. let person = create('Jeremy', []) person = addHobby('programming', person) person

    = addHobby('reading', person) describe(person) // Jeremy likes to do things such as programming and reading
  54. let person = create('Jeremy', []) person = addHobby('programming', person) person

    = addHobby('reading', person) describe(person) // Jeremy likes to do things such as programming and reading
  55. let person = create('Jeremy', []) person = addHobby('programming', person) person

    = addHobby('reading', person) describe(person) // Jeremy likes to do things such as programming and reading
  56. let person = create('Jeremy', []) person = addHobby('programming', person) person

    = addHobby('reading', person) describe(person) // Jeremy likes to do things such as programming and reading
  57. const greet = (greeting, name) => `${greeting}, ${name}` // ..

    const greetInEnglish = name => greet('Hi', name) const greetInSpanish = name => greet('Hola', name)
  58. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  59. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  60. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  61. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  62. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  63. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  64. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  65. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') greetInEnglish('Lambda Squared') // Hi, Lambda Squared greetInSpanish('Lambda Squared') // Hola, Lambda Squared
  66. const greet = greeting => name => `${greeting}, ${name}` const

    greetInEnglish = greet('Hi') const greetInSpanish = greet('Hola') Curried Function Partial Application
  67. greet greeting name = greeting ++ ", " ++ name

    greetInEnglish = greet "Hi" greetInSpanish = greet "Hola"
  68. greet greeting name = greeting ++ ", " ++ name

    greetInEnglish = greet "Hi" greetInSpanish = greet "Hola"
  69. greet greeting name = greeting ++ ", " ++ name

    greetInEnglish = greet "Hi" greetInSpanish = greet "Hola"
  70. greet greeting name = greeting ++ ", " ++ name

    greetInEnglish = greet "Hi" greetInSpanish = greet "Hola"
  71. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  72. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  73. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  74. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  75. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  76. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  77. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  78. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  79. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  80. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  81. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  82. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  83. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  84. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  85. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  86. const toUpper = string => string.toUpperCase() const greet = greeting

    => name => `${greeting}, ${name}` const exclaim = phrase => `${phrase}!` const excitedGreeting = name => exclaim(greet('Hi')(toUpper(name))) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  87. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  88. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  89. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  90. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  91. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, // LAMBDA SQUARED greet('Hi'), exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  92. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), // Hi, LAMBDA SQUARED exclaim, )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  93. const R = require('ramda') const excitedGreeting = name => R.pipe(

    toUpper, greet('Hi'), exclaim, // Hi, LAMBDA SQUARED! )(name) excitedGreeting('Lambda Squared') // Hi, LAMBDA SQUARED!
  94. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  95. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  96. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  97. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  98. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper -- LAMBDA SQUARED |> greet "Hi" |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  99. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" -- Hi, LAMBDA SQUARED |> exclaim excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  100. greet greeting name = greeting ++ ", " ++ name

    exclaim phrase = phrase ++ "!" excitedGreeting name = name |> String.toUpper |> greet "Hi" |> exclaim -- Hi, LAMBDA SQUARED! excitedGreeting "Lambda Squared" -- Hi, LAMBDA SQUARED!
  101. function createOrder(shoppingCart, customer) { let total = 0 shoppingCart.items.forEach(item =>

    { total += item.price }) shoppingCart.discounts.forEach(discount => { total *= 1 - discount }) total *= 1 + shoppingCart.tax total += shoppingCart.shippingCost total = Math.round(total * 100) / 100 return { status: 'new', customer, total } }
  102. function createOrder(shoppingCart, customer) { let total = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts),

    addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  103. function createOrder(shoppingCart, customer) { let total = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts),

    addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  104. function createOrder(shoppingCart, customer) { let total = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts),

    addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  105. function createOrder(shoppingCart, customer) { let total = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts),

    addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  106. function createOrder(shoppingCart, customer) { let total = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts),

    addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  107. const createOrder = customer => shoppingCart => { let total

    = R.pipe( addPrices(shoppingCart.items), addDiscounts(shoppingCart.discounts), addTax(shoppingCart.tax), add(shoppingCart.shippingCost), roundTotal, )(0) return { status: 'new', customer, total } }
  108. createOrder shoppingCart customer = let total = addPrices shoppingCart.items 0

    |> addDiscounts shoppingCart.discounts |> addTax shoppingCart.tax |> add shoppingCart.shippingCost |> roundTotal in { status = "new" , customer = customer , total = total }
  109. createOrder shoppingCart customer = let total = addPrices shoppingCart.items 0

    |> addDiscounts shoppingCart.discounts |> addTax shoppingCart.tax |> add shoppingCart.shippingCost |> roundTotal in { status = "new" , customer = customer , total = total }
  110. createOrder shoppingCart customer = let total = addPrices shoppingCart.items 0

    |> addDiscounts shoppingCart.discounts |> addTax shoppingCart.tax |> add shoppingCart.shippingCost |> roundTotal in { status = "new" , customer = customer , total = total }
  111. createOrder customer shoppingCart = let total = addPrices shoppingCart.items 0

    |> addDiscounts shoppingCart.discounts |> addTax shoppingCart.tax |> add shoppingCart.shippingCost |> roundTotal in { status = "new" , customer = customer , total = total }
  112. -- TYPE MISMATCH -------------------------------------- App.elm The 2nd argument to function

    `createOrder` is causing a mismatch. 25| createOrder myShoppingCart "Tucker" ^^^^^^^^ Function `createOrder` is expecting the 2nd argument to be: { b | discounts : List Float , items : List { a | price : Float } , shippingCost : Float , tax : Float } But it is: String
  113. -- TYPE MISMATCH -------------------------------------- App.elm The 2nd argument to function

    `createOrder` is causing a mismatch. 25| createOrder myShoppingCart "Tucker" ^^^^^^^^ Function `createOrder` is expecting the 2nd argument to be: { b | discounts : List Float , items : List { a | price : Float } , shippingCost : Float , tax : Float } But it is: String
  114. -- TYPE MISMATCH -------------------------------------- App.elm The 2nd argument to function

    `createOrder` is causing a mismatch. 25| createOrder myShoppingCart "Tucker" ^^^^^^^^ Function `createOrder` is expecting the 2nd argument to be: { b | discounts : List Float , items : List { a | price : Float } , shippingCost : Float , tax : Float } But it is: String
  115. conference : String conference = "Lambda Squared" life : Int

    life = 42 greet : String -> String greet name = "Hello, " ++ name formatCurrency : Float -> String formatCurrency amount = "$" ++ toString amount
  116. conference : String conference = "Lambda Squared" life : Int

    life = 42 greet : String -> String greet name = "Hello, " ++ name formatCurrency : Float -> String formatCurrency amount = "$" ++ toString amount
  117. conference : String conference = "Lambda Squared" life : Int

    life = 42 greet : String -> String greet name = "Hello, " ++ name formatCurrency : Float -> String formatCurrency amount = "$" ++ toString amount
  118. type alias Item = { price : Float } type

    alias ShoppingCart = { items : List Item , discounts : List Float , tax : Float , shippingCost : Float }
  119. type alias Item = { price : Float } type

    alias ShoppingCart = { items : List Item , discounts : List Float , tax : Float , shippingCost : Float }
  120. type alias Item = { price : Float } type

    alias ShoppingCart = { items : List Item , discounts : List Float , tax : Float , shippingCost : Float } type alias Order = { status : String , customer : String , total : Float }
  121. type Status = New | Processing | Shipped type alias

    Order = { status : Status , customer : String , total : Float }
  122. createOrder : ShoppingCart -> String -> Order createOrder shoppingCart customer

    = let total = addPrices shoppingCart.items 0 |> addDiscounts shoppingCart.discounts |> addTax shoppingCart.tax |> add shoppingCart.shippingCost |> roundTotal in { status = New , customer = customer , total = total }
  123. Hard to test Hard to follow Code breaks unexpectedly Too

    much code Scary to refactor Oh, null
  124. function getBestFriendLocation(id, users) { let user = users.get(id) let friend

    = users.get(user.bestFriendId) return friend.location }
  125. function getBestFriendLocation(id, users) { let user = users.get(id) let friend

    = users.get(user.bestFriendId) return friend.location }
  126. function getBestFriendLocation(id, users) { let user = users.get(id) let friend

    = users.get(user.bestFriendId) return friend.location }
  127. function getBestFriendLocation(id, users) { let user = users.get(id) let friend

    = users.get(user.bestFriendId) return friend.location }
  128. function getBestFriendLocation(id, users) { let user = users.get(id) let friend

    = users.get(user.bestFriendId) return friend.location } null
  129. function getBestFriendLocation(id, users) { let user = users.get(id) if (user)

    { let friend = users.get(user.bestFriendId) return friend.location } }
  130. function getBestFriendLocation(id, users) { let user = users.get(id) if (user)

    { let friend = users.get(user.bestFriendId) return friend.location } } null
  131. function getBestFriendLocation(id, users) { let user = users.get(id) if (user

    && user.bestFriendId) { let friend = users.get(user.bestFriendId) return friend.location } }
  132. function getBestFriendLocation(id, users) { let user = users.get(id) if (user

    && user.bestFriendId) { let friend = users.get(user.bestFriendId) return friend.location } } null
  133. function getBestFriendLocation(id, users) { let user = users.get(id) if (user

    && user.bestFriendId) { let friend = users.get(user.bestFriendId) if (friend) { return friend.location } } }
  134. getUserName : Id -> Dict Id User -> String getUserName

    id users = Dict.get id users Maybe User
  135. getUserName : Id -> Dict Id User -> String getUserName

    id users = case Dict.get id users of Just user -> user.name
  136. getUserName : Id -> Dict Id User -> String getUserName

    id users = case Dict.get id users of Just user -> user.name
  137. getUserName : Id -> Dict Id User -> String getUserName

    id users = case Dict.get id users of Just user -> user.name user
  138. getUserName : Id -> Dict Id User -> String getUserName

    id users = case Dict.get id users of Just user -> user.name
  139. -- MISSING PATTERNS ------------------------------ App.elm This `case` does not have

    branches for all possibilities. 30|> case Dict.get id users of 31|> Just user -> 32|> user.name You need to account for the following values: Maybe.Nothing Add a branch to cover this pattern!
  140. getUserName : Id -> Dict Id User -> String getUserName

    id users = case Dict.get id users of Just user -> user.name Nothing -> "<anonymous>"
  141. function getBestFriendLocation(id, users) { let user = users.get(id) if (user

    && user.bestFriendId) { let friend = users.get(user.bestFriendId) if (friend) { return friend.location } } }
  142. getBestFriendLocation : Id -> Dict Id User -> Maybe Location

    getBestFriendLocation id users = case Dict.get id users of Just user -> case user.bestFriendId of Just bestFriendId -> case Dict.get bestFriendId users of Just friend -> friend.location Nothing -> Nothing Nothing -> Nothing Nothing -> Nothing
  143. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  144. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  145. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  146. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  147. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  148. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  149. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  150. getBestFriendLocation id users = Dict.get id users |> Maybe.andThen (\user

    -> user.bestFriendId) |> Maybe.andThen (\id -> Dict.get id users) |> Maybe.andThen (\friend -> friend.location)
  151. Hard to test Hard to follow Code breaks unexpectedly Too

    much code Scary to refactor Oh, null
  152. Hard to test Pure Functions Hard to follow Code breaks

    unexpectedly Too much code Scary to refactor Oh, null
  153. Hard to test Pure Functions Hard to follow Declarative Code

    Code breaks unexpectedly Too much code Scary to refactor Oh, null
  154. Code breaks unexpectedly Immutable Data Too much code Scary to

    refactor Oh, null Hard to test Pure Functions Hard to follow Declarative Code
  155. Too much code Curried, Composable Functions Scary to refactor Oh,

    null Code breaks unexpectedly Immutable Data Hard to test Pure Functions Hard to follow Declarative Code
  156. Scary to refactor Strong, Static Types Oh, null Too much

    code Curried, Composable Functions Code breaks unexpectedly Immutable Data Hard to test Pure Functions Hard to follow Declarative Code
  157. Oh, null Maybe and Monads Scary to refactor Strong, Static

    Types Too much code Curried, Composable Functions Code breaks unexpectedly Immutable Data Hard to test Pure Functions Hard to follow Declarative Code