1

So I am going back to some of the basics and found that I am having trouble with the simplest of things. I have a callback that is throwing me an error, I suspect this is a hoisting thing, but have been googling and can't seem to find what I am looking for.

function add (a,b){return a+b;}
function multiply (a,b){return a*b;}


function applyFn(callback) {
    return callback;
};

var f = applyFn(add);

console.log(f); //logs => function add(a,b){return a+b;}

f(3)(4); // returns => Uncaught TypeError: f(...) is not a function(…)

I know that var f gets hoisted to the top with a value of undefined, while the named functions are hoisted intact. When I console log console.log(typeof f) it returns function - so I am a little confused about what is going on...am I on the right track, or is it a different issue completely?

EDIT: for more clarity the applyFn was supposed to be able to use either the add or multiplyfunction, and so it would look more like this:

function add (a,b){return a+b;}
function multiply (a,b){return a*b;}

//I needed to write this function, but nothing else
function applyFn(callback) {
    return function(){};
};

var f = applyFn(add);
var x = applyFn(multiply)

f(3)(4);
x(6)(8);
HolyMoly
  • 2,020
  • 3
  • 22
  • 35
  • 2
    could you please eloberate a bit on why you say `f(3)(4)` and not `f(3,4)`? – EagleRainbow May 20 '16 at 21:32
  • 1
    Are you looking for function `currying`? – KevBot May 20 '16 at 21:33
  • @ EagleRainbow actually this was how the function was called in a coding challenge so I can't give you a straight answer on that - I do know that I have seen it before, but I don't recall exactly why it was done when I saw it. – HolyMoly May 20 '16 at 21:33
  • 2
    Once you call f, it doesn't return a function, it returns the result of the function passed to applyFn. – kinakuta May 20 '16 at 21:33
  • @ KevBot I might be, maybe this is why my google search wasn't getting me anywhere. searching for the wrong thing. will check that out! – HolyMoly May 20 '16 at 21:34

3 Answers3

1

To answer your question, you need to look at what applyFn returns. It takes a function, and simply returns that function. If you assign what it returns, the variable that you assigned to is now simply a reference to the function you originally passed in. In this case, that's the function add and it simply adds two numbers together. When you call f, you're really calling add, which means 1. it needs two arguments and 2. it's going to return the result of adding the two arguments, not another function that you can then call. If your goal is to do currying, then your function needs to return another function, so that it can be invoked:

function adder(num1) {
  return function (num2) {
    return num1 + num2;
  };
}

adder(2)(3);

Here is what I think you're looking for:

function applyFn(func) {
  return function (x) {
    return function (y) {
      return func(x, y);
    };
  };
}

This implementation of applyFn should do what you expect with add and multiply

kinakuta
  • 9,029
  • 1
  • 39
  • 48
  • ahhh that makes it a little clearer - but I am still not 'there' yet... the `applyFn` was supposed to be able to be passed either the `add` or `multiply` function. so there were actually two calls (although I only included one) i will edit my question to make it more clear – HolyMoly May 20 '16 at 21:58
  • 1
    Ok, now I understand. Give me a minute and I'll update my answer to show what you're trying to accomplish. – kinakuta May 20 '16 at 22:03
  • `If your goal is to do currying, then your function needs to return another function, so that it can be invoked` thank you! This solution works. I didn't realize that my problem was a currying, and am now reading up on that and studying your answer :) – HolyMoly May 20 '16 at 22:36
  • 1
    @HolyMoly `applyFn` is actually currying of a binary function. The succinct arrow syntax is suitable for currying functions manually: `const add = x => y => x + y` and `const curry2 => f => a => b => f(a, b)`. Currying is a broad subject: http://stackoverflow.com/a/30249365/5536315 –  May 21 '16 at 09:30
1

your code is not failing at f(3), but at the second call. f(3) is not a function, so f(3)(4) fails.
applyFn should something be more like this:

var applyFn = fn => a => b => fn(a,b);
//aka.
function applyFn(fn){
    return function(a){
        return function(b){
            return fn(a, b);
        }
    }
}

but this is a pretty limited implementation, since it only works on functions with exactly two arguments. Better would be something more dynamically, like:

function _curry(n, f, a){
    var c = function(...args){
        var b = a.concat(args);
        return b.length < n? _curry(n, f, b): f.apply(this, b);
    }
    Object.defineProperty(c, "length", { configurable: true, value: Math.max(0, n-a.length) });
    return c;
}

function curry(n, f, a){
    if(typeof n === "function") a=f, f=n, n=f.length;
    return _curry(n, f, Array.from(Object(a)));
}

var add = curry(function(a, b){ return a + b });

console.log(add, add(3), add(3)(4), add(3, 4));

but on the other hand, the add and multiply-methods don't make sense, the way they are implemented at the moment.
I would never favor add(foo)(bar) or even add(foo, bar) over foo + bar.

the only place where they make sense is in a context like:

arr.map( add(3) );
//or
promise.then( add(3) );

so why not implement them directly as

var add = b => a => a+b;
var multiply = b => a => a*b;

and skip the part with applyFn?

//why b=>a instead of a=>b? consistency:
var subtract = b => a => a-b;
//so that subtract(3) also does exactly what you would think it does
Thomas
  • 3,513
  • 1
  • 13
  • 10
  • Wow @Thomas, thank you so much for expanding on this for me! It gives me a lot to consider. The reason the original problem is written the way it was is because it was part of a coding challenge and all I was to do was create the `applyFn` function. I have never seen the syntax `var applyFn = fn => a => b => fn(a,b);` and would like to learn more about it - can you tell me what term I should be googling to learn more about that? I like the dynamic implementation (although it wasn't necessary for the challenge, but would have been impressive)! Overall, a great addition to the convo, thank you! – HolyMoly May 20 '16 at 23:14
  • 1
    I don't know wether this type of "chaining" lambdas has a name, it's something I came across when learning about functional programming. The Arrow itself has a name: "lambda-expression" or "fat-arrow". But since it is ES6 you'll need a preprocessor like [Babel](//babeljs.io/repl) to use it in production. – Thomas May 20 '16 at 23:25
  • 1
    "_the only place where they make sense is in a context like:_". Ya, currying makes composing of functions much easier and that's really a big deal. That's why `Promise` is composable. Actually this is the crucial point in functional programming. –  May 21 '16 at 15:44
0

Your syntax for executing f is wrong. f(3)(4) should be f(3, 4). Checked it and it works. Check this jsfiddle

iuliu.net
  • 6,666
  • 6
  • 46
  • 69
  • yes f(3,4) will work - and that makes sense. to put in context, this was part of a coding challenge. the thing i was supposed to do was create the `applyFn` function so that the calls to `f` would work. those calls were already defined. With that said, although modifying the calls to f works - I am not sure if that was what was expected of me. Any thoughts? do you think it was an error on the creators of the challenge, or was there another way to make this run without modifying the call? – HolyMoly May 20 '16 at 21:40