What are other uses of functions as data?

Question

In this exercise, the example of shortening a long function name to a short name is given as an application of using functions as data. In particular, we are given this example

is2p2 = checkThatTwoPlusTwoEqualsFourAMillionTimes;

This example seems artificial. Are there other examples where this is useful?

Answer

The use of functions as data in this way is helpful for at least two clear reasons.

  • First is that it enables us to pass functions as parameters to other functions. To be explicit, let’s say that we have two functions, makeSubarray and isEven.

    • makeSubarray accepts two parameters: an array arr and a function select which returns true or false depending on whether an array entry will be in the final array.
    • isEven has one parameter and returns true if it is even and false otherwise.

    We can implement this function as follows:

    function makeSubarray (arr, select) {
       return arr.filter(select);
    }
    

    and we can implement isEven just as simply by

    function isEven (n) {
       return n % 2 === 0;
    }
    

    The important thing to notice is that when we make a call to the makeSubarray function with an array, for example A = [0, 1, 2, 3, 4, 5], and isEven:

    makeSubarray (A, isEven); /* returns [0, 2, 4] */

    the makeSubarray function will essentially execute select = isEven before doing anything else so that the line

    return arr.filter(select);

    uses the correct function to create a subarray. So this way of using functions as data gives us callbacks.

  • Second and finally, there are cases where we write something like function1 = function2 to use the name function1 as a synonym for function2 when the name function1 is for some reason easier to type/remember than function2. The example doesn’t need to be as drastic as

    is2p2 = checkThatTwoPlusTwoEqualsFourAMillionTimes;

    but can be as simple as writing const dist = EuclideanDistance; when using a library that provides many different distance functions but you only plan to use the EuclideanDistance function and would prefer not to write it out completely multiple times – e.g. it may be obvious from context that the only distance function you could use is the euclidean distance.

15 Likes

Hello! Perhaps I’m being dumb here but…

How is it possible that in the example of makeSubarray function, when isEven is invoked -as an argument of this function- n is taken as an element of the array A?

I still don’t get why the language inteprets that n HAS TO BE an element in A. I am not sure whether I’m explaining myself properly…

Thank you!

1 Like

Hey there. To be clear, are you asking how isEven can determine what n should be when we call the function makeSubarray like this: makeSubarray ( A, isEven ) ?

isEven is known as a predicate function. This type of function always returns a boolean. When used as an argument in the filter method, the list we are filtering is iterated and each element passed to isEven, whereby it is appended to the result if the return value is True.

The n in,

function isEven (n) {
   return n % 2 === 0;
}

is just a local variable, but as the function is a callback for the filter method, n will be an element of the inputed array.

14 Likes

Maybe I’m confused but I dont get Why each element from array is passed to isEven method. Could you explain in more detail? Thanks.

Say we have an array of numbers…

a = [12,22,34,54,65,77,23,13,94,81,65]

and we have a utility function (a predicate, to be exact)…

function isEven (n) {
    return n % 2 === 0;
}

and we want an array of only even numbers taken from the array. We can use a number of approaches but JS gives us an iterator that does the job real well…filter which takes a predicate function as its callback.

evens = a.filter(isEven)

As the method iterates over the array, a, it passes each value to the callback (that will be n, the parameter of that function) and appends the value to the new array, evens if the return value of the callback is true.

console.log(evens)    //  [12, 22, 34, 54, 94]
9 Likes

Nice explanation - the method a.filter is constructed to iterate over all of the elements of the array. This is the design of this particular method. This is similar, for example, to the method str.toUpperCase, which is constructed to convert all of the characters of the string to uppercase.

1 Like

So, this is what I understood:

  • A predicate function is basically a helper function (can you explain what predicate functions are in more detail?)

  • The function that takes another function as an argument is called a high-order function

  • The filter method takes a predicate function as an argument (making it a high-order function) and passes each element of the array it is being called on as an argument of the predicate function

  • Finally, it will return an array containing all the elements that returned true when passed into the predicate function as arguments

I need help understanding what predicate functions are

predicate

grammar - logic

verb: state, affirm, or assert (something) about the subject of a sentence or an argument of a proposition.

A predicate function only has two possible returns… true or false.

Instead of having a separate isEven function, we can also do this:

let numberArray = [1, 2, 3, 4];

var evens = numberArray.filter(currentItem, index, array){
return currentItem % 2 === 0;
}

if we were console.log() the variable evens, this is what we would get:

[2,4,6];

The above is same as:

let numberArray = [1, 2, 3, 4];

function isEven(number){
return number % 2 === 0;
}

var evens = numberArray.filter(isEven);

printing variable to the console will print the same result as the first example.

Welcome, @system5697865867,

It might come down to maintenance and re-usability. When we write a helper function it can be shared across the whole program so makes it re-usable. It is better to use this approach than write functions inside iterators. They become a one use object and a waste of space.

yes ! good point regarding code re-usability !

1 Like