Thanks for this video! I think I am missing something...If currying is what makes a function accept a variable number of arguments at a time, then I would say that using the bind method as shown in this video is in fact another way of currying.
So, notice that when we call curry(sumFourNumbers), we don't pass in any arguments? That's because we're actually creating a new version of that function that is curried -- meaning it accepts ONE argument at a time, and returns a function expecting the NEXT argument. When we call sumFourNumbers.bind(null, 1, 2), however, we have provided some of the expected arguments and received a function that expects the REMAINING arguments (3, 4). The returned function has not been curried. It still expects all of the remaining arguments at once. If we called sumFourNumbers.bind(null), we haven't partially-applied the function at all. The returned function still expects all of its arguments, and it would not accept them one at a time (meaning it is not curried). And if you tried to call curriedSumFourNumbers(1, 2), the 2 would be ignored because a curried function only accepts one argument at a time. Feel free to follow-up if that did not clarify the differences for you :)
I've seen other people explain currying as a special form of partial application.... In any case, as it's explained on the video, they really are 2 ways of achieving the same thing, i.e. pre-apply arguments to functions to reuse behaviour with different parameters; the only difference is that any function can be partially applied while you have to write a function on a certain way to curry it.
A curried function is really useful when using the common patterns in functional programming. As a super quick example... suppose you have an array of numbers: const nums = [1, 2, 3] And the curried function: const add = x => y => x + y You can then do... const newNums = nums.map(add(2)) Now you have a new array of numbers that has been incremented by 2. You leveraged an existing function (add), without needing to wrap it in another function to provide the argument '2'. This example may seem contrived, but the concept works well in more complex situations as well. A more obvious example might be partially applying a function where only one argument differs for a number of use cases as a way of composing new functions by gradually adding specificity... // pseudo code const requester = method => user => fetch(user, method) const syncRequest = requester('sync') We now have a sync request function we can use on any user... const syncUser1 = syncRequest(user1) const syncUser2 = suncRequest(user2)
Thanks for the video, but I'm still unclear about the reasoning why one would choose one method over the other. I understand what partial application and currying are, but I can't think of any practical reason why I would use currying over partial application (the latter being something I use extensively). Around 6 minutes into the video, you mentioned something which I think is the main idea you were trying to communicate, but I didn't really understand the significance of it. You emphasised that "a curried function *knows* that it's curried, whereas a partial function is just an entirely new function". But why is this important? What is useful about a curried function knowing that it requires 2 more applications before it spits out a variable, compared to a partial function that has 2 remaining arguments to fill? Am I correct in interpreting this to be the key difference between the two procedures?
So, you can partially-apply a curried function, but not all partially-applied functions are curried. A curried function expecting more than 1 argument will always return a new, partially-applied function when given its first argument (or second, third, etc.). But you can partially-apply a non-curried function, which will also give you back a new function that expects the remaining arguments. The difference just comes down to how you use/call the functions... const add = (x, y) => x + y const curriedAdd = x => y => x + y const nums = [1,2,3,4,5] const newNums1 = nums.map(add.bind(null, 1)) console.log(newNums1) // [2,3,4,5,6] const newNums2 = nums.map(curriedAdd(1)) console.log(newNums2) // [2,3,4,5,6] Does that clear up the different at all? .map() receives a partially-applied function in both cases, but curriedAdd was already curried, so partially-applying it was much easier.
Okay, so I've read and re-read your example quite a few times now and I think I can narrow down what I'm confused about. What if you simply defined a function (forgive me if my JavaScript syntax is incorrect, I don't often use the language) const partialAdd1 = add.bind(null, 1) Now curriedAdd(1) and partialAdd1 are equally easy to use and reuse. Why would I specifically want to use Currying? In my more native functional language of Mathematica, partial application is obtained through the use of pure, anonymous functions. This is quite easy to read once the syntax is understood, so I'm struggling to think of a reason why I would use Currying over partial application for that language...
great video thanks
Good video, THANKS!
I think you can enhance your curry function for currying like f(1,2)(3) or f(1)(2,3) or even f()(1)(2,3).
Thanks for this video! I think I am missing something...If currying is what makes a function accept a variable number of arguments at a time, then I would say that using the bind method as shown in this video is in fact another way of currying.
So, notice that when we call curry(sumFourNumbers), we don't pass in any arguments? That's because we're actually creating a new version of that function that is curried -- meaning it accepts ONE argument at a time, and returns a function expecting the NEXT argument.
When we call sumFourNumbers.bind(null, 1, 2), however, we have provided some of the expected arguments and received a function that expects the REMAINING arguments (3, 4). The returned function has not been curried. It still expects all of the remaining arguments at once.
If we called sumFourNumbers.bind(null), we haven't partially-applied the function at all. The returned function still expects all of its arguments, and it would not accept them one at a time (meaning it is not curried).
And if you tried to call curriedSumFourNumbers(1, 2), the 2 would be ignored because a curried function only accepts one argument at a time.
Feel free to follow-up if that did not clarify the differences for you :)
I've seen other people explain currying as a special form of partial application.... In any case, as it's explained on the video, they really are 2 ways of achieving the same thing, i.e. pre-apply arguments to functions to reuse behaviour with different parameters; the only difference is that any function can be partially applied while you have to write a function on a certain way to curry it.
What is the purpose/practical application of all of this?
A curried function is really useful when using the common patterns in functional programming. As a super quick example... suppose you have an array of numbers:
const nums = [1, 2, 3]
And the curried function: const add = x => y => x + y
You can then do...
const newNums = nums.map(add(2))
Now you have a new array of numbers that has been incremented by 2. You leveraged an existing function (add), without needing to wrap it in another function to provide the argument '2'.
This example may seem contrived, but the concept works well in more complex situations as well.
A more obvious example might be partially applying a function where only one argument differs for a number of use cases as a way of composing new functions by gradually adding specificity...
// pseudo code
const requester = method => user => fetch(user, method)
const syncRequest = requester('sync')
We now have a sync request function we can use on any user...
const syncUser1 = syncRequest(user1)
const syncUser2 = suncRequest(user2)
Thanks for the video, but I'm still unclear about the reasoning why one would choose one method over the other. I understand what partial application and currying are, but I can't think of any practical reason why I would use currying over partial application (the latter being something I use extensively).
Around 6 minutes into the video, you mentioned something which I think is the main idea you were trying to communicate, but I didn't really understand the significance of it. You emphasised that "a curried function *knows* that it's curried, whereas a partial function is just an entirely new function". But why is this important? What is useful about a curried function knowing that it requires 2 more applications before it spits out a variable, compared to a partial function that has 2 remaining arguments to fill? Am I correct in interpreting this to be the key difference between the two procedures?
So, you can partially-apply a curried function, but not all partially-applied functions are curried.
A curried function expecting more than 1 argument will always return a new, partially-applied function when given its first argument (or second, third, etc.). But you can partially-apply a non-curried function, which will also give you back a new function that expects the remaining arguments.
The difference just comes down to how you use/call the functions...
const add = (x, y) => x + y
const curriedAdd = x => y => x + y
const nums = [1,2,3,4,5]
const newNums1 = nums.map(add.bind(null, 1))
console.log(newNums1) // [2,3,4,5,6]
const newNums2 = nums.map(curriedAdd(1))
console.log(newNums2) // [2,3,4,5,6]
Does that clear up the different at all? .map() receives a partially-applied function in both cases, but curriedAdd was already curried, so partially-applying it was much easier.
Okay, so I've read and re-read your example quite a few times now and I think I can narrow down what I'm confused about. What if you simply defined a function (forgive me if my JavaScript syntax is incorrect, I don't often use the language)
const partialAdd1 = add.bind(null, 1)
Now curriedAdd(1) and partialAdd1 are equally easy to use and reuse. Why would I specifically want to use Currying? In my more native functional language of Mathematica, partial application is obtained through the use of pure, anonymous functions. This is quite easy to read once the syntax is understood, so I'm struggling to think of a reason why I would use Currying over partial application for that language...