2
\$\begingroup\$

I wrote a little Compose function, which takes a variable number of arguments of type function and then calls each of those in order, passing in the value of the previously called function.

My function works just like I want it to, however since the function provides a way to program functionally, I figured it's application should be functional as well--but it's not.

The Compose function:

const Compose = (...functions) => {
    return val => {
        let i = 0,
            len = functions.length,
            fnResult = functions[i](val);

        while (++i < len) {
            fnResult = functions[i](fnResult);
        }

        return fnResult;
    };
};

Application:

const add7 = num => num + 7;
const squared = num => num * num;
const subtract13 = num => num - 13;

const add7ThenSquareThenSubtract13 = Compose(add7, squared, subtract13);

add7ThenSquareThenSubtract13(5);   // 131
add7ThenSquareThenSubtract13(0);   // 2
add7ThenSquareThenSubtract13(100); // 11436

What it's doing under the hood:

// Let's say 'val' is 5.

// 1. Call add7(val), result is 12.
// 2. Call squared(12), result is 144
// 3. Call subtract13(144), result is 131

// subtract13( squared( add7(val)  ) ) === 131

Anyone have any idea how I can make the logic inside the Compose function more functional? I am having a hard time since I am just now learning to think in a functional way. Is it even possible? I don't know of any ways to loop an array without using for or while.

UPDATE:

Never mind, I figured it out. Didn't think I could use reduce for this but I suppose I can:

const Compose = (...functions) => {
    return val => {
        return functions.reduce((prevVal, currFunc) => {
            return currFunc(prevVal);
        }, functions[0](val));
    };
};

It's not pretty, but it works--and it's functional. ;)

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

One little suggestion on your reduce version is to make the initial value not the first function's result. This way, if ever the arguments is empty functions[0](val) won't call a missing function and throw up. Also makes reduce call the callback for each item, which makes it less of a cognitive burden.

Also, arrow functions that have expressions as its body implicitly returns the expression's value. You can have something as tiny as the following:

const Compose = (...args) => v => args.reduce((p, c) => c(p), v)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.