My partner just started watching Mattias Johansson's FunFunFunction series on Functional Programming, so to help and also give myself a refresher I've put together this massive post on the series.

Hope you find these useful.

Anonymous functions

Anonymous functions are functions that are dynamically declared at runtime. They are declared using the function operater instead of the function declaration.

// named function
function triple(x) {
  return x * 3
}
// anonymous function
var triple = function(x) {
  return x * 3
}

Higher Order functions

Higher Order Functions help us with composition, by allowing us to place a lot of little functions into bigger functions and so on; so we break down the task into little pieces which can help making it more readable and easier to understand.

var animals = [
  { name: 'peter', species: 'rabbit'},
  { name: 'james', species: 'dog'}
]

// function inside a value
var isDog = function(animal) {
  return animal.species === 'dog'
}

var dog = animals.filter(isDog) // ['dog']
var otherAnimals = animals.reject(isDog) // ['rabbit']

// to return what we need,
// breaking down the problem.

Map function

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
    // Return element for new_array
}[, thisArg])

Map is a higher order function that iterates through an array of objects, unlike filter it doesn't throw away items that don't match the filter it transforms them.

var animals = [
  { name: 'peter', species: 'rabbit'},
  { name: 'james', species: 'dog'}
]

// es5 version
var names = animals.map(function(x) { return x.name })

// es6 version
var names = animals.map((x) => x.name)

// result
// > ['peter', 'james']

Reduce function

arr.reduce(callback[, initialValue])

The reduce() method executes a reducer function (that you provide) on each member of the array resulting in a single output value.

Unlike other transforms you provide a function to operate on each member of the array, returning a single value.

var orders = [
  { amount: 250 },
  { amount: 250 }
]
var totalAmount = orders.reduce((sum, order) => {
  return sum + order.amount
})

// result
// 500

We can go beyond it with

// data.txt
// john smith blender 80 2

var output = fs.readFileSync('data.txt', 'utf8')
  .trim()
  .split('\n')
  .map(line => line.split('\t'))
  .reduce((customers, line) => {
    // if blank return [], otherwise store in iterator
    customers[line[0]] = customers[line[0]] || []
    // attach to iterator
    customers[line[0]].push({
      name: line[1],
      price: line[2],
      quantity: line[3]
    })
    return customers
  })

// create json string from output with 2 spaces indentation
console.log(JSON.stringify(output, null, 2))

// result
{
  "john smith": {
      "name": "blender",
      "price": "80",
      "quantity": "2"
  }
}

Closures

A closure is the combination of a function and the lexical environment within which that function was declared.

Languages such as Java provide the ability to declare methods private, meaning that they can only be called by other methods in the same class.

JavaScript does not provide a native way of doing this, but it is possible to emulate private methods using closures. Private methods aren't just useful for restricting access to code: they also provide a powerful way of managing your global namespace, keeping non-essential methods from cluttering up the public interface to your code.

For every closure we have three scopes:

  • Local Scope (Own scope)
  • Outer Functions Scope
  • Global Scope
// global scope
var e = 10;
function sum(a){
  return function(b){
    return function(c){
      // outer functions scope
      return function(d){
        // local scope
        return a + b + c + d + e;
      }
    }
  }
}

console.log(sum(1)(2)(3)(4)); // log 20

It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.

Currying

Currying is the process of taking a function with multiple arguments and returning a series of functions that take one argument and eventually resolve to a value. The original function volume takes three arguments, but once curried we can instead pass in each argument to three nested functions.

Alternative it's a function that doesn't take all it's arguments up front. It expects you to give it the first argument and then the function returns another function which you are supposed to call with the second argument which in turn will return a new function which you are supposed to call with the third argument and so on... until all the arguments are provided then the function at the end of the chain will be the one that returns the value that you actually want.

let dragon =
  name =>
    size =>
      element =>
        name + ' is a ' +
        size + ' dragon that breathes ' +
        element + '!'

let fluffy = dragon('fluffy')
let tiny = fluffy('tiny')

console.log(tiny('lightning'))

// => flully is a tiny dragon that breathes lightning

Recursion

Recursion is when a function calls itself until it's done.

let categories = [
  {id: 'animals', parent: null},
  {id: 'mammals', parent: 'animals'},
  {id: 'cats', parent: 'mammals'},
  {id: 'dogs', parent: 'mammals'},
  {id: 'chihuahua', parent: 'dogs'},
  {id: 'labrador', parent: 'dogs'},
  {id: 'persian', parent: 'cats'},
  {id: 'siamese', parent: 'cats'},
  {id: 'ghosts', parent: null},
  {id: 'casper', parent: 'ghosts'}
]

let makeTree = (categories, parent) => {
  let node = {};
  categories
    // filter out every category whose
    // parent matches the one given
    .filter(c => c.parent === parent)
    .forEach(c =>
      // then for each node id run makeTree
      // with using the id as the parent
      node[c.id] = makeTree(categories, c.id))
  // the return the node until we're done
  return node;
}

console.log(
  JSON.stringify(
    makeTree(categories, null)
    , null, 2));

// output
{
  "animals": {
    "mammals": {
      "cats": {
        "persian": {},
        "siamese": {}
      },
      "dogs": {
        "chihuahua": {},
        "labrador": {}
      }
    }
  },
  "ghosts": {
    "casper": {}
  }
}

Promises

new Promise(executor);

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

A Promise is in one of these states:

  • pending: initial state, neither fulfilled nor rejected.
  • fulfilled: meaning that the operation completed successfully.
  • rejected: meaning that the operation failed.

We did this in a previous article but to recall the code:

function getCurrentTime(onSuccess, onFail) {
  // Get the current 'global' time from an API using Promise
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      // randomly decide if the date is retrieved or not
      var didSucceed = Math.random() >= 0.5;
      didSucceed ? resolve(new Date()) : reject('Error');
    }, 2000); // delay by 2000, 2 seconds before responding.
  })
}

getCurrentTime()
  // onSuccess or resolve
  .then(currentTime => getCurrentTime())
  // manipulates the previously returned value
  .then(currentTime => {
    console.log('The current time is: ' + currentTime);
    return true;
  })
  // onFail or reject
  .catch(err => console.log('There was an error:' + err))

Functors

Functors are simply something that can be mapped over.

Why is this useful? because it allows us to build functions that can operate on data that they were not originally designed to work with.

The Map or Filter methods have nothing to do with functors, it’s objects that implement maps that are functors.

console.log([ 2, 4, 6 ].map(x => x + 3))
// => [ 5, 7, 9 ]

With arrays

const array = [ 2, 4, 6 ]
const addThree = (x) => x + 3
const mappedArray = array.map(addThree)

console.log(mappedArray)
// => [ 5, 7, 9 ]

Or objects

const dragons = [
  { name: 'Fluffykins', health: 70  },
  { name: 'Deathlord', health: 65000 },
  { name: 'Little pizza', health: 2 },
]

const names =
  dragons.map(dragon => dragon.name)

console.log(names)

// result
[
    'Fluffykins',
    'Deathlord',
    'Little pizza'
]

Functor laws:

1. Transformation of contents

The basic idea is that the map method of the functor takes the contents of the Functor and transforms each of them using the transformation callback passed to map.

In this case, this function here is the transformation callback — it transforms a dragon object into just a dragon name.

2. Maintain structure

The second thing that Array#map does in order qualify Array for the title of Functor is that it maintains structure.

If you call .map on an array that is three long, it returns an array that is three long. It never changes the length of the array, it doesn’t return null.

3. Returns a new functor

The third and final thing that Array#map does in order to be functor-material is, the value that map returns must be a functor of the same type.

Because of this, we can chain map calls like this:

const dragons = [
  { name: ‘Fluffykins’, health: 70  },
  { name: ‘Deathlord’, health: 65000 },
  { name: ‘Little pizza’, health: 2 }
]
const nameLengths =
    dragons
        .map(dragon => dragon.name)
        .map(dragonName => dragonName.length)

console.log(nameLengths)
// [ 10, 9, 12 ]

Here we have the same array of dragons, but after we extract the names, we get the length of each name. Because the first map function returns a functor, we can keep calling map on it. You can also do map map map map chaining with promises, or any other functor.

Streams

A stream is a flow of values that will eventually arrive.

// load file handler
const fs = requre('fs')
// load stream library supporting promises
const highland = require('highland')
// read file in utf8 format
highland(fs.createReadStream('customers.csv', 'uft8'))
  //split into each line
  .split()
  // break out each line into single items by ,
  .map(line => line.split(','))
  // take that array and return an object
  .map(parts => ({
    name: parts[0],
    numPurchases: parts[1]
  }))
  // filter out purchases above 2
  .filter(customer => customer.numPurchases > 2)
  // map thru customers returning name
  .map(customer => customer.name)
  // console log each result using the previous response
  .each(x => console.log('each ', x))

// customers.csv
Mattias,2
King Midas,4

// Result
each: King Midas

Monads

In Brief

A monad is a design pattern that allows structuring programs generically while automating away boilerplate code needed by program logic.

Monads achieve this by providing their own data type, which represents a specific form of computation, along with one procedure to wrap values of any basic type within the monad (yielding a monadic value) and another to compose functions that output monadic values (called monadic functions).

The essence of monads:

  • Functions map: a => b which lets you compose functions of type a => b
  • Functors map with context: Functor(a) => Functor(b), which lets you compose functions F(a) => F(b)
  • Monads flatten and map with context: Monad(Monad(a)) => Monad(b), which lets you compose lifting functions a => F(b)

Array, Stream, Tree, Promise are all Functors (as we can map them), but the last two Stream and Promise are Monads because we can flatMap them.

Remember functors are simply something that can be mapped over, why? it allows us to build functions that can operate on data that they were not originally designed to work with.

let capitalizePortuguease =
  portuguese.map(_.capitalize)

Streams will map new stream, arrays will map new arrays, trees will map new trees, etc.

Whats a flatMap?

flatMap is just like map, except flatMap does NOT expect the mapper to return a value.

Instead, flatMap expects the mapper to return a functor containing the value, and flatMap will take that functor and flatten into it's actual value.

A flatMap maps each element of an array using a mapping function, then flattens the result into a new array.

let arr = [1, 2, 3]

arr.map((x) => [x * 2])
// [[2], [4], [6], [8]]

arr.flatMap(x => [x * 2])
// [2, 4, 6, 8]

Promises are Monads

let getInEnglish = require('./getInEnglish')
let _ = require('lodash')

let whenFood = new Promise(function(resolve) {
  setTimeout(() => resolve('vaca'), 2000)
})

whenFood
  // get english of 'vaca' via the Promise
  .then(getInEnglish)
  // capitalize it
  .then(_.capitalize)
  // print it to the console
  .then(food => console.log(food))

When we look at the code above it's similar to flatMap, which takes one thing but doesn't necessarily return the same.

Here even though .then doesn't look like .flatMap it's doing the same, taking one chain and returning something else.

If we use map on an array it will still return something like an array, same thing with trees, streams & promises.

But if we use flatMap it will return a flattened array, not the same structure as was given and that's why Promises are monads.

You can map the data, or you can flatMap on the data.

fetch('/api/user')
  // get response
  // flatMap, flatten it returning .json
  .then(response => response.json)
  // hand .json to the next in the chain
  .then(response => {
    console.log(response)
  })

This video will help: