0

I am running into an error: Uncaught TypeError TypeError: multipliers.reduce(...) is not a function. I was looking at currying and partial application. I expected multiply function to correctly invoke through an array of multipliers. Can someone please explain what I'm missing in my multiply function?

multiply function that multiplies integers, but in a special way. The function's output can be invoked repeatedly until you call it with no arguments. For example, multiply(3)(4)(5)() should return 3 * 4 * 5 = 60. I am using a helper function solution(multipliers) that takes all the multipliers and then passes them to multiply as described above.

Input

multipliers: [3, 4, 5]

Output

60

Code

function multiply(x) {
    return function(y) { // anonymous function
        return function(z) { // anonymous function
            return x * y * z;
        }
    }
}

// this function lets you invoke something like multiply(3)(4)(5)() with dynamic arguments
function solution(multipliers) {
    return (multipliers.reduce((prev, arg) => {
        if (prev) {
            return prev(arg);
        }
        return multiply(arg);
    }, null))();
}

console.log(solution([3, 4, 5]));
imparante
  • 503
  • 9
  • 21
  • 1
    `multiply(3)(4)(5)` returns `3 * 4 + 5`. No extra `()` is necessary. No extra `solution` is necessary. You already curried the operation by declaring nested functions. – Bergi Jun 17 '23 at 04:00
  • 2
    You cannot do currying with variadic (= taking arbitrary number of arguments) functions. Don't try to mix them. – Bergi Jun 17 '23 at 04:01
  • The idea is the input to be an array of multipliers. That is why I am using the `solution` function. – imparante Jun 17 '23 at 04:23
  • Your `multiply` function also performs addition, which is not what you described it to be. For example, you described that `multiply(2)(3)(5)()` should return `2 * 3 * 5 = 60`. However, your `multiply` function when applied as `multiply(2)(3)(5)` returns `2 * 3 + 5 = 17`. In addition, as you can see it doesn't take an arbitrary number of inputs. Instead, it always takes exactly 3 inputs. So, your question is inconsistent. Please elucidate what you're actually trying to do. – Aadit M Shah Jun 17 '23 at 04:48
  • Apologies, I have updated my implementation to `return x * y * z` to match the example. – imparante Jun 19 '23 at 19:09
  • You can look at this [Code Review question](https://codereview.stackexchange.com/questions/153979/create-a-function-with-an-undetermined-number-of-successive-calls) if you are interested in a more general solution. – M0nst3R Jun 19 '23 at 19:13
  • @imparante why are you calling `multipliers.reduce` as an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)? That's what's causing the error in the first place. – M0nst3R Jun 19 '23 at 19:19

5 Answers5

0

You have to push all parameters to an array before calling an array method on it. Or else you can use the arguments parameters inside the function to get all the parameters.

Can you share how the function has been called?

0

Use the multiply function as the initial value for the reduce call, and drop the final ():

function solution(multipliers) {
    return multipliers.reduce((prev, arg) => prev(arg), multiply);
}
console.log(solution([3, 4, 5]));

function multiply(x) {
    return function(y) {
        return function(z) {
            return x * y + z;
        }
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you, I would like to maintain solution function as-is without changes and only update the `multiply function`. The inner-most return is `return x * y * z`. I have just updated my implementation to match the example. – imparante Jun 19 '23 at 19:14
  • 1
    @imparante Sure you could replace `return x * y * z;` by `return function() { return x * y * z; };`, but really you should not. Your `solution` function is wrong and overly complicated, you should fix it – Bergi Jun 19 '23 at 21:12
0

Your multiply function is defined incorrectly. If you want multiply(3)(4)(5)() to evaluate to 60 then you need to define the multiply function as follows.

// x is required, y is optional, both are numbers
const getMultiply = (x) => (y) =>
  typeof y === "undefined" ? x : getMultiply(x * y);

// 1 is the identity element of multiplication
const multiply = getMultiply(1);

console.log(multiply(3)(4)(5)()); // 60

Once you define multiply correctly, you can define solution as follows.

// x is required, y is optional, both are numbers
const getMultiply = (x) => (y) =>
  typeof y === "undefined" ? x : getMultiply(x * y);

// 1 is the identity element of multiplication
const multiply = getMultiply(1);

const solution = (multipliers) =>
  multipliers.reduce((f, x) => f(x), multiply)();

console.log(solution([3, 4, 5])); // 60
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Thank you, I would like to maintain solution function as-is without changes and only update the `multiply function` – imparante Jun 19 '23 at 19:16
0

You are invoking the call to multipliers.reduce(...) as an IIFE. This won't work because the result of calling the reduce in your code is not a function, it's instead a number.

In the code you provided, you essentially wrote:

function solution(multipliers) {
  return (60)(); // 60 here being the result of calling the reduce
}

Which explains the error you received.

All you need to do is omit the IIFE call. Your function becomes:

function solution(multipliers) {
    return multipliers.reduce((prev, arg) => {
        if (prev) {
            return prev(arg);
        }
        return multiply(arg);
    }, null);
}

Finally, I suggest looking at some of the other answers here or in this question for a better implementation of your multiply function to make it more generic.

M0nst3R
  • 5,186
  • 1
  • 23
  • 36
-1

I was able to modify only the multiply function using currying thanks to @ghassen-louhaichi's link to a related question: Create a function with an undetermined number of successive calls.

function multiply(x) {
    return function() {
        if (arguments.length == 0) {
            return x;
        } else {
            return multiply(x * arguments[0]);
        }
    }
}

// this function lets you invoke something like multiply(3)(4)(5)() with dynamic arguments
function solution(multipliers) {
    return (multipliers.reduce((prev, arg) => {
        if (prev) {
            return prev(arg);
        }
        return multiply(arg);
    }, null))();
}

console.log(solution([3, 4, 5]));

The first call to multiply, returns the inner function. depending on the number of arguments passed to the inner function, it returns the value of multiply's argument as it is or it calls again ´multiply´ with the updated running total (thus returning again the inner function to be called again).

The limitation (of this implementation) is that you HAVE TO make a final call with no arguments to have to final value.

imparante
  • 503
  • 9
  • 21