Functional Programing

In JavaScript

λ

What is functional programming?

An alternative to procedural or object-oriented programming

functions are the basic building block

functional programming

  • minimizes side-effects
  • avoids mutation
  • encourages explicit inputs and outputs

why?

  • easy to think about in isolation
  • easier to test
  • higher level of abstraction
  • easier to refactor

Some basic patterns

map and filter

var R = require('ramda')
//ramdajs.com

R.map(
    (x) => 2 * x,
    [1, 2, 3, 4, 5])
//returns [ 2, 4, 6, 8, 10 ]

R.filter(
    (x) => x % 2 === 0,
    [1, 2, 3, 4, 5])
//returns [ 2, 4 ]

reduce

R.reduce(
    (sum, x) => sum + x,
    0,
    [1, 2, 3, 4, 5])
// returns 15

// (0, 1)  =>  1

// (1, 2)  =>  3

// (3, 3)  =>  6

// (6, 4)  => 10

// (10, 5) => 15

curry

not a sauce! :P

var add_3 =
    R.curry((a, b, c) => a + b + c)

//All of these return 6
add_3(1, 2, 3)
add_3(1, 2)(3)
add_3(1)(2, 3)
add_3(1)(2)(3)
//All ramda functions are auto-curried

var doubles = R.map((x) => 2 * x)
var evens = R.filter((x) => x % 2 === 0)
var sum = R.reduce((x, y) => x + y, 0)

doubles([1, 2, 3, 4, 5])
//returns [ 2, 4, 6, 8, 10 ]

evens([1, 2, 3, 4, 5])
//returns [ 2, 4 ]

sum([1, 2, 3, 4, 5])
//returns 15

compose

var f = (x) => 2 * x
var g = (x) => x + 1
var h = (x) => x / 2

var fogoh =
    R.compose(f, g, h)

/* fogoh = (x) =>
    2 * ( (x / 2) + 1) */

fogoh(2) //returns 4

compose + curry

var is_number = (x) => !isNaN(x)
var sum = R.reduce((x, y) => x + y, 0)

var sum_what_you_can =
    R.compose(
        sum,
        R.filter(is_number),
        R.map(parseInt))

sum_what_you_can([
    12,
    "42",
    "potatoes",
    87
])
//returns 141

Objects

var purchase = {
    name: 'hover board',
    price: 10000
}

var get_price = R.prop('price')

get_price(purchase)
//returns 10000
var change_price = R.assoc('price')

change_price(100, purchase)
/*
returns {
    name: 'hover board',
    price: 100
}
*/
var price_lens =
    R.lens(
        R.prop('price'),
        R.assoc('price'))

var apply_discount =
    R.curry((discount, purchase) =>  
        R.over(
            price_lens,
            R.subtract(R.__, discount),
            purchase))

apply_discount(100, purchase)  
/* returns {
    name: 'Hover Board',
    price: 9900
} */
var price_formatter_lens =
    R.lens(
        R.prop('price'),
        R.assoc('formatted_price'))

var add_formatted_price =
    R.over(
        price_formatter_lens,
        format_dollars)

add_formatted_price(purchase)
/*
returns {
    name: 'hover board',
    price: 10000,
    formatted_price: '$10,000'
}
*/

No side Effects

//modifies value and returns it
var apply_discount = function (discount, purchase) {
    purchase.price -= discount
    return purchase
}

apply_discount(100, purchase)
/*changes value of purchase to {
    name: 'Hover Board',
    price: 9900
} */

apply_discount =
    R.curry((discount, purchase) =>
        R.over(
            R.lensProp('price'),
            R.subtract(R.__, discount),
            purchase))

apply_discount(100, purchase)
/* returns {
    name: 'Hover Board',
    price: 9900
} */
var add = (a, b) => {
    var sum = a + b
    console.log(sum)
    return sum
}

explicit inputs

//implicit
var purchase = {
    name: 'hover board',
    price: 10000,
    apply_discount: function (discount) {
        this.price -= discount
    }
}

//explicit
apply_discount =
    R.curry((discount, purchase) =>
        R.over(
            R.lensProp('price'),
            R.subtract(R.__, discount),
            purchase))

explicit outputs

var change_item_name =
    function (purchase, name) {
        purchase.name = name
    }

change_item_name(purchase, 'light saber')
/* changes purchase to
{ name: 'light saber', price: 10000 }
*/

change_item_name = R.assoc('name')

change_item_name('flying car')
/* returns
{ name: 'flying car', price: 10000 }
*/

Easy to think about in isolation

var add = (a, b) => a + b

Easier to test

describe('add', () => {
    var add = require('../add.js')

    it(
        'should return the sum of its two arguments',
        function () {
            expect(add(1, 1)).toEqual(2)
        })
})

easy to refactor

var format_dollars_cents =  
    R.compose(
        R.join('.'),
        (money) => [
            format_dollars(money[0]),
            money[1] ? money[1].slice(0, 2) : '00'],
        R.split('.'),
        R.toString)

format_dollars_cents(100000)  
//returns $100,000.00

format_dollars_cents(100000.234)  
//returns $100,000.23

format_dollars_cents(.234)  
//returns $0.23

higher level of abstraction

var comma_separate = (width) =>  
    R.compose(
        R.join(','),
        R.map(R.reverse),
        R.reverse,
        R.splitEvery(width),
        R.reverse)

var format_dollars =  
    R.compose(
        R.concat('$'),
        comma_separate(3),
        R.toString)

format_dollars(100000)  
//returns $100,000

debugging

var comma_separate = (width) =>
    R.compose(
        R.join(','),
        R.reverse,
        R.splitEvery(width),
        R.reverse)

var format_dollars =
    R.compose(
        R.concat('$'),
        comma_separate(3),
        R.toString)

format_dollars(100000)
//returns '$001,000', what gives?
var tap = function (x) {
    console.log(x)
    return x
}

var comma_separate = (width) =>
    R.compose(
        R.join(','),
        tap,
        R.reverse,
        R.splitEvery(width),
        R.reverse)

//prints [ '001', '000' ]
var comma_separate = (width) =>
    R.compose(
        R.join(','),
        R.map(R.reverse),
        R.reverse,
        R.splitEvery(width),
        R.reverse)

This is just the beginning

  • Functors
  • Maybe
  • Either
  • Monads
  • Applicative Functors
  • Category Theory

Resources

Professor Frisby's Mostly Adequate Guide to functional programming

https://drboolean.gitbooks.io/mostly-adequate-guide/content/

Ramda

ramdajs.com

lodash

lodash.com

lodash-contrib

github.com/node4good/lodash-contrib

Learn you a haskell for great good

learnyouahaskell.com

funkyjavascript.com

Functional Programming In JavaScript

By Steve Smith

Functional Programming In JavaScript

Learn how to use functional programming concepts in your javascript for fun and profit.

  • 979