0

I am having a problem with one of the assignments in my javascript programming course.

Assignment:

Create a function called "calculate" which expects three functions as parameters and when called returns one of those functions as a result.

Everytime you call

let result = calculate(add, subtract, multiply)(1,3)

it should return a different result.

I have tried different approaches and got different errors like calcuate is not a function or multiply is not defined.

This is what I have tried so far:

function add(num1, num2){
  return num1 + num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(add, subtract, multiply){
  
  let randNum = Math.floor(Math.random() * 3) + 1

  switch(randNum){
    case 1:
      let add = add(num1, num2)
      break;

    case 2:
      let subtract = subtract(num1, num2);
      break;

    case 3:
      let multiply = multiply(num1, num2);
      break;

  }

}

let result = calculate(add(2,4), subtract(2,4), multiply(2,4))
console.log(result);

I did some research on currying, but I can't see what I am getting wrong. Any help would be gratefully appreciated.

3
  • 2
    "Everytime you call...it should return a different result." That's not a very clear assignment. What should it return the fourth time, if I've already returned the addition, subtraction, and multiplication results? Commented Apr 22, 2019 at 11:12
  • This (or the answer to it) isn't really an example of currying, not unless your instructor has some truly unnecessarily complicated solution for it. The simple solution, if using randomness, can easily be a one-liner. Commented Apr 22, 2019 at 11:13
  • Maybe I was bad at translating the assignment. I think what is wanted, is that if you call the function calculate it should randomly choose one of the 3 functions it received as parameters. Commented Apr 22, 2019 at 11:17

4 Answers 4

2

This isn't a great example for teaching currying. I think what the instructor/course is trying to get across here is that when you do:

let result = calculate(add, subtract, multiply)(1,3)

you're calling a function (calculate) that returns a function (one of the three you pass it, I guess picked at random though the assignment is unclear), and then you're calling that function (by using (1,3) on the result of the calculate(...) call.

calculate can be a one-liner:

function calculate(...fns) {
    return fns[Math.floor(Math.random() * fns.length)];
}

or in ES5:

function calculate() {
    return arguments[Math.floor(Math.random() * arguments.length)];
}

Live Example:

function add(num1, num2){
  return num1 + num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    return fns[Math.floor(Math.random() * fns.length)];
}

let result = calculate(add, subtract, multiply)(1,3);
console.log(result);


A more useful example to teach currying would be:

let result = calculate(add, subtract, multiply)(1)(3);
// ----------------------------------------------^^

Notice that we're calling the result of calculate with 1, then calling the result of that with 3. Then, calculate would need to wrap the function it picks in another function that collects the 1 and then waits to be called with the 3:

function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => {
        return (b) => {
            return fn(a, b);
        };
    };
}

or more concisely, but less clearly:

function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => (b) => fn(a, b);
}

Live Example:

function add(num1, num2){
  return num1 + num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    const fn = fns[Math.floor(Math.random() * fns.length)];
    return (a) => (b) => fn(a, b);
}

let result = calculate(add, subtract, multiply)(1)(3);
console.log(result);

The function returned by calculate, when called, remembers a and returns a new function; that function, when called, gets b and calls fn(a, b) to get the result.

That example picks the function up-front, but it could pick it at the end as well:

function calculate(...fns) {
    return (a) => (b) => fns[Math.floor(Math.random() * fns.length)](a, b);
}

Live Example:

function add(num1, num2){
  return num1 + num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(...fns) {
    return (a) => (b) => fns[Math.floor(Math.random() * fns.length)](a, b);
}

let result = calculate(add, subtract, multiply)(1)(3);
console.log(result);

Sign up to request clarification or add additional context in comments.

1 Comment

"or more concisely, but less clearly" Until you get used to arrow functions. Even then, though, if the nesting goes on, clarity can suffer (at least for me).
2

You could take a random function from the arguments and return this function for another call with parameters.

const
    add = (a, b) => a + b,
    subtract = (a, b) => a - b,
    multiply = (a, b) => a * b,
    calculate = (...args) => args[Math.floor(Math.random() * args.length)];

let result = calculate(add, subtract, multiply)(1, 3);

console.log(result);

Comments

1

calculate should return one of the functions so the result of the calculate function should be called with the actual params:

function add(num1, num2){
  return num1 + num2;
}

function subtract(num1, num2){
  return num1 - num2;
}

function multiply(num1, num2){
  return num1 * num2;
}

function calculate(add, subtract, multiply){

  let randNum = Math.floor(Math.random() * 3) + 1

  switch(randNum){
    case 1:
      return add
      break;

    case 2:
      return subtract
      break;

    case 3:
      return multiply
      break;

  }

}

console.log(calculate(add, subtract, multiply)(2, 4));

1 Comment

Code dumps are not useful answers. Say what you did, and why. (Before posting, not as an edit.)
0

You have two problems in this part of the code, inside your calculate function:

  switch(randNum){
    case 1:
      let add = add(num1, num2)
      break;

    case 2:
      let subtract = subtract(num1, num2);
      break;

    case 3:
      let multiply = multiply(num1, num2);
      break;


  1. You're calling you math functions (ej. add(num1, num2)) inside calculate. This will return a number but the expected behaviour is that it will return a function, so that you can call it with further parameters:

    let result = calculate(add, subtract, multiply)(1,3)
    


  2. Your calculate function is not returning any value. Thus, when your doing let result = calculate(...), result will always be undefined.


Instead of this, your calculate function should return a function:

    function calculate(add, subtract, multiply){

      let randNum = Math.floor(Math.random() * 3) + 1;

      switch(randNum){
          case 1:
          return add;

          case 2:
          return subtract;

          case 3:
          return multiply;
      }
    }

Demo: https://jsbin.com/jiholifife/edit?js,console


Note the difference: your function calculate is now returning a function.
This is possible due to the fact that functions in JavaScript are First-Class objects: a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.