Check out a free preview of the full The Good Parts of JavaScript and the Web course:
The "Function Challenge 3" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:

In this challenge, you will write the twice(), reverse(), composeu(), composeb(), and limit() functions.

Get Unlimited Access Now

Transcript from the "Function Challenge 3" Lesson

>> [MUSIC]

>> Douglas: Write a function twice that takes a binary function and returns a unary function that passes its argument to the binary function twice. So by twice I mean this. We've got the add function we're going to add 11 twice. Okay, that'll produce 22. So we're going to automate that.

[00:00:20] We're gonna make a twice function. We can pass add to that and it will create a double function which does the same thing. We could also pass the multiply function to twice. It will produce a square function which will square things. Now, I intentionally misspelled the word double.

[00:00:39] Because in some implementations, double is reserved word. And if you spell it correctly, you'll get a syntax error which is inexcusable. Since double isn't even used in this language. But so, I misspelled it. I recommend that you misspell it too for the same reason. So here is twice.

[00:00:58] Twice takes a binary function. Returns a function that takes an argument. Returns result of calling the binary function with that arguments twice. So got twice? Very good, if you didn't get it, write it down. If you're gonna need it for another one. Any questions before we go on to the next one?

>> Speaker 2: Maybe a dumb question. I was trying to figure out if there was a way to define this using [INAUDIBLE].
>> Douglas: There probably is but it's probably just as well that you didn't.
>> Speaker 2: All right. So if we did, would we wanna change to that implementation?
>> Douglas: It's up to you.

[00:01:34] The most important thing today is that it works.
>> Douglas: Okay, ready to move on? Okay, here's the next one. Write reverse, a function that reverses the arguments of a binary function. So we're gonna to pass to reverse the sub function that we wrote this morning. And it returns the bus function which is subtract backwards.

[00:02:00] So if we pass 3 and 2 to bus, we'll get -1. Okay, so here is reverse. reverse takes a binary function and returns a function that takes the first and second argument, returns result to calling the binary function with the second and first argument. So who got reverse?

[00:02:18] Very good. So this is how will write it next year. We'll be able to reverse any number of arguments. So we're trying to get into practical stuff now. So you might imagine, you've got two APIs and you need to make them work together but they were not designed to work together.

[00:02:35] So they're calling sequences are incompatible. And you could rewrite one of them to be more like the other but that's too much work or you could write a wrapper function around every entry point of one but that's too much work too. With this approach, we could let functions do that work.

[00:02:51] So we can have functions write wrappers, which will allow us to use the matter operability or interchangeably, okay? So ready for the next one? Write a function composeu that takes two unary functions and returns a unary function that calls them both. So we're gonna take the double in the square function that we wrote earlier.

[00:03:17] And we're gonna pass them both to composeu. And then, we'll pass the function that returns 5 and it will return 100. And it'll do that by taking the five and doubling it and then taking that and squaring it. So here is composeu. Composeu takes functions f and g.

[00:03:40] It returns a function that takes an argument and returns the result of calling g(f(a)). So who got compose you? Very good. The tricky thing about this one was that nested function invocations are written inside out. Which lexically looks backwards and say just need to get the g before the f even though it's called later.

[00:04:04] So this introduces a way of programming which is kind of like adding Unix pipes except at the function level. That we can take existing functions and kinda string them together. And pass values through them and it'll go through this chain of functions until something comes out the other end.

[00:04:23] So next year when we write this function, we'll allow to take not two functions but any number of functions and you can just program a whole series of things. Until then, you could call composeu you several times each time adding a new function to the list. Sort of like currying, I guess.

[00:04:38] Okay, any questions about that? Ready for another one?
>> Douglas: Anybody? Yeah, all right. Good, good, all right.
>> Douglas: So Write a function composeb that takes two binary functions and returns a function that calls them both. So we're going to pass add and mul to composeb and they will return the function.

[00:05:03] And if we pass it, 2, 3, and 7, it'll be turned in 35.
>> Speaker 2: [COUGH]
>> Douglas: So here is composeb, composeb takes two functions f and g. Returns a function that takes a, b, and c. And returns result of calling g(f(a and b) and c). So who got composeb?

[00:05:24] Really good, you guys are doing great.
>> Douglas: Feeling good? Yeah? Okay, wanna do another one? I've got another one. So let's go. Write a limit function that allows a binary function to be called a limited number of times. So, we're going to pass the add function to limit, and say you can call it, you can use it one time.

[00:05:48] And that will produce a limited add function. We could then give that to a third party, and the third party can call it once, and it works just right. But if they called a second time, all it does is return undefined. Doesn't do anything else. Okay, you could think of, you could pass a wish function to limit and say you only get three wishes.

[00:06:10] The wish function can make any number of wishes but the function that we hand you will have a limit on. Does the function you pass have to be a binary function?
>> Douglas: Let's say, yes.
>> Speaker 2: Okay.
>> Douglas: In the future, we want to work with anything but for today we'll just say binary function.

[00:06:33] So here's limit. limit takes a binary function and a count. And it returns a function that takes two arguments. If the count is greater than or equal to one, it documents the count and returns the result of calling the binary function with the two arguments. Otherwise, it will return undefined.

[00:06:53] So from this point on, the functions are starting to get a little bit more complicated. So it's unlikely that you did the same thing I did. So from this point on, I'm going to ask who got something that works? Okay, very good. Anyone do something interesting? A different approach?

>> Speaker 3: Use a variable instead of I had two variables instead of just one.
>> Douglas: Okay, and where did you put them?
>> Speaker 3: Before return function, I said max. No, max was, I said i equal to zero. And the count I use max. And then each time I run function, it just incremented i one.

>> Douglas: Great, very good. So, anybody else?
>> Speaker 3: Well- Yeah, I'm a little confused like how to count or.
>> Speaker 3: How is this being stored, how the number of time has been?
>> Douglas: Well, we're using a closure, right? So, the other function has access to the variables of parameters of the other function.

[00:07:59] So it seems the count that is changing that [INAUDIBLE].
>> Speaker 3: Do you need to return undefined there?
>> Douglas: Yeah, so let’s that a really good question. And that's why underlined the statement because I want to talk about it. So, there are two schools of thought on that statement.

[00:08:18] One is, this is completely unnecessary. Because in JavaScript, if a function falls off the bottom it returns undefined. So this is just a waste of space. There is no reason to say this. The other school of thought is that part of the contract for this function is that it returns undefined when the limit is reached and so.

[00:08:38] By explicitly returning and defined, we're providing self documenting code.
>> Douglas: I think both points of view are valid, I've not been able to decide which one is better. See, you'll see me flip flopping on this. The thing that is clearly bad would be saying, just return semi colon cuz that doesn't accomplish either thing.

[00:09:01] It's a waste of space and it isn't explicit about what's getting returned. Yes?
>> Speaker 3: And you answered my question right there.
>> Douglas: Okay, anybody else?
>> Speaker 3: I had something maybe less clever. I had a local variable called, which I initialized to zero, which was the number of calls made.

>> Douglas: Okay, and the local variable was stored above-
>> Speaker 3: Yeah, it's like above the, before the return.
>> Douglas: Brilliant, okay, very good.