Separate functions from rules
Functions are nouns.
The curried
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)
})