Partial application: I understand the basic and the logic behind it but

I don’t get what is happening on these lines of code: above all when it uses the rest/spread operator.

const partial = (fn, ...argsToApply) => {

return (...restArgsToApply) => {
return fn(...argsToApply, ...restArgsToApply)
}
}

const getApiURL = (apiHostname, resourceName, resourceId) => {
return `https://${apiHostname}/api/${resourceName}/${resourceId}`
}

const getResourceURL = partial(getApiURL, 'localhost:3000')

const getUserURL = userId => {
return getResourceURL('users', userId)
}

const getOrderURL = orderId => {
return getResourceURL('orders', orderId)
}

const getProductURL = productId => {|
return getResourceURL('products', productId)|
}

partial is a curried function. When you assign partial to getResourceURL the latter will return

return (...restArgsToApply) => {
  return fn(...argsToApply, ...restArgsToApply)
  }

Then, when you call getUserURL it returns

return fn(...argsToApply, ...restArgsToApply)

where argsToApply takes 'localhost:3000' and restArgsToApply will be an array ['users', userId]. Then, these arguments will be passed to getApiURL (or in general the passed function fn). The same applies for getOrderURLand getProductURL.

const partial = (fn, ...argsToApply) => {
  return (...restArgsToApply) => {
    return fn(...argsToApply, ...restArgsToApply)
  }
}

So, the first line:

const partial = (fn, ...argsToApply) => {

That is a rest operator. This parameter list is “saying”, "take the first param that is passed and store it as fn, then take whatever parameters are left over and store them in the array argsToApply.


On line 2:

  return (...restArgsToApply) => {

This is a rest operator. It is saying, "take however many parameters there are, and store them in an array called restArgsToApply.


On the third line:

    return fn(...argsToApply, ...restArgsToApply)

These are both spread operators. They are each saying, “take this single array and break it apart into its individual elements”. So, if argsToApply stored 3 args and restArgsToApply has 4, then those 3 from argsToApply will be the first 3 params passed and then the 4 from the other will be the next 4, totaling 7.


Yeah, it’s a little confusing at first. Part of this is that spread and rest operators look alike and I often have to stop and look for context. The other problem is that “rest operator” I think is not a very good name. I think something like “gather operator” would have been clearer.

Thank You both. I start grasping what is happening but there is still an obstacle in my mind. I am not sure what the second line is taking as argument.

When I call getUserURL(“Goku”), this function call partial() function. A this point the partial function takes as arguments getApiURL and localhost:3000.

The second line is the hardest part to understand: what …restArgsToApply is taking? I think that is taking ‘users’ and userId (but I am not 100% how this is happening).

Basically now I have all the argument that I need the get the API: I call the function fn that takes as argsToApply: ‘localhost:3000’, and as restArgsToApply: ‘users’ and user Id. thanks to the spread operator this three arguments are extended respectively to apiHostname, resourceName and resourceId.

am I on the right track? could you please go a bit deeper on the second line (…restArgsToApply)?

Thank You.

Let me abstract it into a different application. Put another way,

// Don't worry about this, it's just a function that takes a bunch or parameters and adds them up.
const addThemUp = (...nums) => nums.reduce((a, c) => a + c)


const partial = (fn, ...argsToApply) => {
  return (...restArgsToApply) => {
    return fn(...argsToApply, ...restArgsToApply)
  }
}

const func1 = partial(addThemUp, 1, 2, 3)
console.log(func1);
// This returns a function.
// It is analogous to 
// (...restArgsToApply) => {
//   return addThemUp(1, 2, 3, ...restArgsToApply)
// }

const sum = func1(4, 5, 6);
console.log(sum);
// This returns the sum, 21.
// It is analogous to going
// (...restArgsToApply) => {
//   return addThemUp(1, 2, 3, 4, 5, 6)
// }
// and calling it with (4, 5, 6) as parameters so really it is
// addThemUp(1, 2, 3, 4, 5, 6)

The second line is the hardest part to understand: what …restArgsToApply is taking?

It is part of that second function, the one that is in func1:

// (...restArgsToApply) => {
//   return addThemUp(1, 2, 3, ...restArgsToApply)
// }

It is the rest operator. It is saying, “I don’t care how many parameters are sent, just scoop them all up and put them in an array.” It’s doing the same thing as the rest operator in the first line. The difference is when. The rest operator in the first line is getting run when partial is called and that returns a function that has that second line as the first line of the returned function. That spread operator won’t get run until the returned function (the one stored in func1) gets run. It just sits there.

So, when we get to line 3 (of the partial function), we have two arrays (from the rest operators) that get spread out - instead of arrays, they are now lists of parameters.

It may seem odd to use the rest operator and then immediately undo it with the spread operator, but it’s actually a really handy and clean way to deal with variable numbers of parameters. It looks weird at first, but you get used to it.

Additionally, this thing of functions returning partial functions is a confusing subject - cut yourself some slack. Seriously, don’t worry if this is hard. Just do your best and maybe look up some youtube videos on “javascript curried function”. But don’t worry if it isn’t clear right away. I do this all the time and sometimes I still have to stop and look at it twice.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.