Separate functions from rules

In notebook:
FrontEndMasters Hardcore Functional
Created at:
2017-01-27
Updated:
2017-07-15
Tags:
Functional Programming JavaScript Fundamentals
Functions are nouns. 

Make operations on functions. Intension vs Extension (-9:31, not really followed)
We should consider functions as nouns. They can passed around and can be considered as one whole entity. If we consider functions extensionally and not intentonally we can just see what they represent and what they do but not care how they do it.

Every function is a single-valued collection of pairs. 
E.g.:

(-2, -1)
(0, 0)
(2,1)

Every value will result in another number, and each value only gives back one number. 
Domain
all the numbers on the left hand side of the list (above, in the parenthesis). What is eligible to be put in the function. 
Range
all the numbers on the right hand side of the list. The results that you can have.

Separate arity from functions

It's about passing arguments to your functions. You can separate your function so that you can give as many arguments as you want and it won't affect your function. Usually you would give less arguments than what it requires at first and with subsequent calls you  provide the other arguments. 

  function get(property, object) {
  return object[property]
}

var people = [{name:...}, ...]
This removes the ​object.property​ dot operator of the JavaScript language, but can do much more with as he will demonstrate later. 

Consider the ​people​ list above:
  function getPersonName(person) {
  return get('name', person)
}

var names = people.map(getPersonName)
It pulls the name from the list out. 

Now, what if we had magical function that does this:
  //
// The magical function
// 

var names = people.map(get('name'))
So we're no longer using ​getPersonName​, but just ​get​, but with only one argument.

The first part of the trick is to the order of the arguments in ​get​. first ​property​ then ​object​. This way we can bake in the ​name​ and the object can be anything (like in the ​map​, we map over different objects)
The second part is currying
  function curry(fn) {
  return function () {
    // checks if the number of arguments
    // it received is less 
    // than the arguments the function expected
    // at the declaration
    if(fn.length > arguments.length) {
      // keep note of the arguments
      // that were given to the function
      var slice = Array.prototype.slice
      var args = slice.apply(arguments)
      return function () {
        // then merge the args at the first run
        // with the current arguments
        return fn.apply(
            null, args.concat(slice.apply(arguments))
        )
      }
    }
    // if there are as many arguments passed
    // as the "original" declaration
    // just pass them along
    return fn.apply(null, arguments)
  }
}
It only looks so complicated because of JavaScript syntax...

NOTE:
Function.length ☞  Specifies the number of arguments expected by the function.

The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified.

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

The curried ​get​ function

  var get = curry(function (property, object) {
  return object[property]
})

var names = people.map(get('name'))
NOTE:
The map() method creates a new array with the results of calling a provided function on every element in this array.

So ​people.map(get('name'))​ is the same as
  var namegetter = get('name') // get will return a new function, with the 'name' argument baked in

var names = people.map(function (aperson) {
  namegetter(aperson)
})