Build curried functions

Brian Lonsdorf
InstructorBrian Lonsdorf
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 6 years ago

We see what it means to curry a function, then walk through several examples of curried functions and their use cases.

[00:00] Here, we have a function add. It takes an x and a y and just adds them. We'll call it here to get the result 3. Now, let's define another function called increment. We are just going to take some y, and call add 1 with y. This should just increment. Let's say increment 2 to get 3 here. There we are.

[00:17] If you look at it, what we've done here is just given add one of its arguments. We've preloaded add with the number 1. We can use a better technique here to actually capture this idea of preloading a function with some argument to create a new function. That technique is called curry.

[00:31] What we can do here is instead of it taking both x and y at the same time, we can take x first and then that returns a function that takes y. If we parenthesize this, it might make a little bit more sense here. It takes an x and returns a function, and takes a y. That will add them two together.

[00:47] Here, we can just call add 1, here 1 is x, which returns us this function y here. If we were to look at this x would be 1. We've given add 1 and it's returned us this function. It takes a y, but x is already remembered to be 1. Then, it could add those two together. Now, increment should still work, still adding 3, 2, I think.

[01:02] Why would anybody do this? This is a decent demonstration here where we say we're going to give add one of our arguments. Let's look at some more examples. We have this function modulo that takes a dividend and a divisor, giving it divisor and a dividend. It will just, modulo and divisor.

[01:23] If we want to make a function isOdd, that is if the number is odd the remainder should be 0or it should be 1. If it is even, it should be 2. What we can do here is call modulo 2. Instead of taking, again, a function that takes...we'll call this the dividend and then we pass that in here.

[01:40] We can essentially cross out these arguments by saying...instead of taking them both at once, take one at a time, and then we can remove this whole extra error, because this is now a function.

[01:52] Modulo 2 returns us a new function waiting for the rest of its arguments, this dividend here. Now, we can call isOdd on 2. We get 0because 2 is not odd. If we call 21, we should get 1. 1 if it's odd, 0if it's even.

[02:07] Let's do another one here. Let's make a filter. This one, we're just going to wrap the normal filter, it takes predicates and some array xs and what is called xs.filter predicate. We're just wrapping it in this new style, this curried style instead of calling .syntax on it.

[02:22] That way, we can actually say a new function, how about getAllOdds, which is just filter applied to isOdd. Now, this is a function waiting for a list, this list here with the predicate being isOdd. We can say, getAllOdds with 1, 2, 3, 4 and we should just end up with 1 and 3. There we are. This technique of preloading functions with arguments tends to be rather useful.

[02:49] Let's look at one more example to get a good feel for this. What we can do here is make replace, and again, we're just going to wrap the standard call to replace. We take a string and we call replace, and some regex and something to replace it with.

[03:04] In the case of filter, we give it a predicate first, and that's because we want to partially apply our filter with a function. We don't have a list at this point. We have another function though. You end up wanting to put your data last.

[03:15] In that vein, what we're going to do is give it our regex first, then the thing to replace, and then finally our string is our last argument. That way when we say, let's go ahead and make a censor function, which will replace any vowel here, a, e, i, o, u with ig here.

[03:33] Then the second argument is what to replace it with. Remember, this is a function, we have to give it what to replace with. Let's give it a * here. We're calling this function with its second argument, returning a third function waiting for its string.

[03:44] That's why string comes last. We don't have the string here in the definition of censor. Now, we can call censor with the string, hello world -- hello world -- and we can run this and we will get the censored version. That's why you wait for your data as the last argument so you can keep building up these other functions.

[04:01] Lastly, just like filter let's make a map here just to demonstrate one useful tool here. We'll take some f and xs what is called map with f. We're just simply wrapping the standard function call but it's curried, it takes f function first, then our argument.

[04:14] What we can do here is make another function, censorAll, simply by calling censor with map around it. What this has done is, say, instead of censor working on one thing, we'll work on an array of things just by partially applying map. Now, we can call censorAll with hello and world, just like that.

[04:36] We've transformed this function to work on single values to a function that works on arrays just by surrounding it in map, and there's our results. That's what currying does. You separate each argument returning a new function, and you typically want your data to be the last argument.