 All right, let's get started, hey? Hello? My name is Tony Morris. I'm going to talk to you today about list folds. It's a beginner level talk. I'm hoping to transfer some knowledge to you to think about list folds so that you can really understand how they work. Who was at the intro workshop yesterday? Oh, that's nearly half the people. We did list folds yesterday. And for the other half of you, we're going to do it again. OK? A bit of a different format. All right. So this is where I'm from, Brisbane, Australia. I don't actually live on the river, but it's in the state of Queensland on the east coast of Australia. That state is currently on fire at the moment. If you've looked at the news, there's fires all up and down. It's very smoky. Had to fly an airplane through it the other day. Couldn't see. That's OK. If you come and visit me, I'll show you around. That's the east coast of Brisbane. Pacific Ocean just off there to the left. I work at the Queensland Functional Programming Lab. So that's a team of seven or eight people. And we're sponsored by the federal government and the state government to do functional programming. Yeah. So we need to talk to the Indian government. So we write Haskell most of the time. Our team. We're a team of programmers. And we use a lot of languages, but mostly Haskell. And we work under what's called the CSIRA. It's the Commonwealth Scientific Research Organization. OK, so what's the goals for today? Who's heard of left and right folds on lists? And for those of you who have your hand up, what is that the end of your knowledge? That's it. You've just heard of it. You've heard of it, but that's it. A few people. My goal today is to transfer you some knowledge so that you can understand internally what they do. I get a lot of questions about them in my email. Can you tell me when to use the right one? What does this one do? What does that one do? How do I think about them? I want to answer these questions. So first, we have to talk about what exactly is a list. What is a list? A list is either nil, an empty list, that carries no information. It's just an empty list. Or it has one element and then another list. Think about lists this way. I can make any list this way. Using either nil or cons. Nil being empty list, cons having one element and then another list. It's never anything else. It's always nil or cons. So this is the Haskell signature for them. So we say that nil is just a list of elements A. It's the empty list. And cons takes an A, the first element, and then a list, the rest of the list, and it makes a new list. OK? The word cons, by the way, goes back to the 1950s. So we tend not to make up new words when they're that well-established. Here is the Haskell source code. What this says is we're declaring a data type called list, carrying elements of type A. It's made with nil, that has nothing, or with cons that has an A and another list of A. How can we make lists using this? For example, here is a list that has one element, the number 12. I've called cons. I've passed in one element, 12, and then the rest of the list, nil. There is no rest of the list. What about the list ABC? I call cons. I pass in the letter A, and I have to pass in another list. So then I call cons, and then the letter B needs to pass in another list, cons, c, nil. I can make any list using cons and nil. OK? That's the definition of a list, or a cons list, as they're sometimes called. Sometimes, if you type into Google right now, you might see nil's spelt square brackets. Just so you know, if you ever come across that, it's the same thing. And sometimes you'll see cons as just a colon, or sometimes a double colon, depending on the language or whatever. So here's the list, one, two, three. One, cons, then a whole new list. Two, cons, and then a whole new list. Three, cons, and then nil. This is the definition of a list and how we make them. OK? So when we talk about folds, we're talking about these kinds of lists. Footnote, there are languages for which this is not true. They talk about other kinds of lists. But if you just think about, like if we consider C sharp, for example, that has an aggregate function, which is a kind of fold, but it works on other kinds of lists, so it's not really a fold. So I'm gonna just talk about it in terms of cons lists. So you've probably heard of, yet? You probably, I think about nearly two thirds of you put your hand up. You've heard of left and right folds. You've heard of them, that's it. Walking down the street one day, and someone said left and right folds, and then you just kept walking. Right? In Haskell, they're called fold iron fold L. Scala, they're called fold right and fold left. And C sharp has this function called aggregate, which is essentially a fold left, kind of. So just to be clear on our goals. When do I know to use a fold? What problem do I have so that I'm gonna use a fold? Which one am I gonna use? And finally, what do they do? What is a good way to think about what they do? You might have seen these fold diagrams that are on the internet. They're pretty good diagrams. They're quite accurate. They don't really help, I think, in my experience. Like, you know, people come up to me and they say, can you just tell me exactly what a right fold does? And I show them this diagram, and they go, I still don't know what a right fold does. It needs some explanation. This is the left fold diagram. Didn't help. And sometimes you've probably heard of this. A right fold does folding from the right and a left fold from the left. Not only is it not helpful, it's not even true. So I've also heard this. We're gonna use the right fold when we need to work with an infinite list. This is not correct, okay? So sometimes they're just not right. So, we're looking for an intuition that doesn't require to already have an expert knowledge that is satisfactory, that you feel like you've understood something and it's not wrong. If you've ever read a monitor tutorial on the internet, you'll find that they meet the first two goals. Like, consider burritos. You don't need a deep understanding of burritos. Burritos are satisfactory. But monads are not burritos. Sorry, they're not. So I'm hoping to achieve all three of these. In practice, or the way to think about these two different functions is very different, okay? The way the intuition for each of them is quite different. So I'm going to try to talk about them each differently. So let's talk about what fold L does, fold left. It takes three values. Okay? It takes a function F, B to the element type to B. It takes another element B, and then it takes the list that we're doing the fold on. I also write the C-sharp type signature there if you prefer to read that, I do not. How does it take these three values to return a value? It does this loop, okay? So everyone's heard of a loop, right? They taught that back at loop school. I remember first year undergrad, loop school. So if we look at this loop, who's written a loop like that before? Everyone's written a loop like something like that. And importantly, these are the three components of the loop that we get to change with fold left, okay? We get to pass in a function, what to do on each iteration of the loop. So that's the B to A to B, that thing there, the F. The Z there is the B, so that's what the value to start the loop at. And finally, the list, the thing that we're looping on, or fold lefting on. So let's look at some real code. Let's add up the numbers in a list. Here's a list of numbers, add them up. Okay, what am I gonna replace Z with? Well, zero, yeah? What about F? Plus, you were listening yesterday, excellent. That will add up the numbers in the list. Left fold, giving the accumulator through the loop, R, the element A, add them, start the loop at zero, do it on the list. This will add up the numbers in a list. And if you ever reduce that expression there, you end up with just plus. Just do plus on each iteration of the loop. What about multiplication? What do we replace F with, the function? What are we gonna do on each iteration of the loop? We're gonna do multiplication. What are we gonna start the loop at? One, we had that debate yesterday. Some people say zero. It's gonna happen if I put zero there. Zero, yeah. One is the identity for multiplication. One is the thing that does nothing to multiplication. Like, one times X gives me X, it did nothing to X. Okay, there it is. It's gonna multiply the numbers in a list. And there's the code. This is real Haskell code. How to multiply all the numbers in a list. Left fold, spin on each part of the loop with multiplication, start at one. Fold left as a loop. I mean, if you open up the source code to fold left, you won't see a loop there. You'll see all sorts of crazy recursion and then you'll see a sec or something like that to make it faster. But all you need to think about is it does a loop, that loop. How do you reverse a list? This was a trick question yesterday. So I taught everyone about fold right and then I said, okay, now reverse a list. And they tried to do it using fold right. And it ended up very slow. Let's do it with a left fold. What am I gonna replace Z with if I'm gonna reverse that list? Nill, the empty list. And on each iteration of that loop, I'm going to take that element and put it on the front of that list. That will reverse the list. Left fold through the list, pull the elements off the front and put them on the front of a new list, Nill. It'll come back reversed in linear time. There it is. I have a function. There's the list being accumulated R. There's the element off the list. Cons it. Do that in each iteration of the loop, start at Nill. This will reverse a list. That's the real code. Actually, yeah, I told a bit of a story yesterday. I once went for a job interview about 15 years ago. No, maybe longer 20 years ago. And the interviewer said to me, reverse a list. And I said, okay, what language? It was actually a C-sharp job. And then the guy said, you know, any language you prefer. I said, okay, fold left, flip cons Nill. And I didn't get the job. So I don't recommend you answer that in that way. But it is correct. That will reverse a list. What about the length of a list? What are we going to do? We're going to start the loop at zero. And for each of the accumulating value R, we're going to ignore the element A and just add one to R. That will compute the length of a list. So the function plus one, given R, ignore A to R plus one. Do that on each spin of that loop and we'll add up the numbers in R. Sorry, it'll compute the length of a list. There's the code. I essentially read this word here as do a loop. That's how I like to think of it. On each iteration of the loop, do that, start there. That will compute the length of a list. This is just a point free way of writing that same function. Const means ignore the element and then do plus one on each iteration. If I said to you, take all of the loops that you've written and refactor out all of their differences, you'll end up with a fold left. They're exactly this loop. That is to say, I don't need a little footnote here to say just kidding, it's not quite precise. It is exactly that loop. Which means that any question we might ask about a left fold, we can also ask about that loop and we'll get the same answer. For example, will that loop ever work on an infinite list? Nope. An infinite list, by the way, is one that doesn't have nil. It's just cons all the way to infinity. If I put that into a left fold or into that loop, it just will never give me an answer. It'll sit there and heat up the world a bit more, set Queensland on fire a bit more. It's easy to transfer this information because you've probably already heard of loops. I've used your existing knowledge to transfer this information. Left fold is a loop. For right folds, there is no existing thing that I can use to transfer the information. You just simply need to commit to the definition of a list, which is nil or cons. So let's commit to that right now. That's what a list is. Folding to the left is a loop. The fold right function. Well, it takes a function A to B to B. Then it takes a B, so A is the element type in the list and it takes a list and it returns a B. There it is written in Haskell. There it is written in, actually that's Java, I think. I don't know. One of those languages. What does it do? How does it take that function, that B, and that list and give me a B? It performs constructor replacement. So constructors, remember, are nil and cons. They are the two things that construct lists. The expression fold right with the function FZ on a list. We'll go through that list in no particular order and replace every cons with F and nil with Z. If it sees a nil, which it might not because it might be infinite. So if we take this list A, B, C, D, and I fold right with FZ on that list, I'll get back whatever value is replacing cons with F and nil with Z. Whatever that is. So if we consider this is like a list of numbers, A, B, C, and D are all numbers and I wanted to add them up. I can replace F with plus and Z with zero and I will add them all up. So that's another way of adding up the numbers in a list or multiply, let's multiply them. So here's a list of numbers, 4567. I'm gonna replace cons with multiplication and nil with one. Now that will multiply the numbers in a list. Fold right did construct a replacement. The important thing about fold right to recognize is it doesn't do it in any particular order. There is an associativity order but there is not an execution order. So that is to say some people might say to me, fold right starts at the right side of the list. This can't be true because I'm gonna pass in an infinite list which doesn't have a right side and I'm going to get an answer. If it started at the right, it went a really long way and it's still going. So that's what I should see if that statement is true but I don't see that. It associates to the right. It didn't start executing from the right. It's a subtle difference. What if I have a list of booleans and I wanna add them all up? What am I going to replace nil with? Not 99. So I have this list. It's true, cons, true, cons, false, cons, true and I replace nil with true and cons with and like this. It will and them all up. So there's the code. Right fold replacing cons with and and nil with true. It doesn't do it in any order. I could have an infinite list of booleans. Suppose I had an infinite list of booleans and it started at false, cons, false, something and I said, fold right and true. I should get that false and I do. So clearly it didn't start from the right. It never went there. It just saw the false and stopped. How about appending two lists? Here's a list and here's a list. I don't want to append them. Do you agree with me that I'm going to go through this list and replace cons with cons and nil with that list? Who agrees with me on that? That's how you append two lists. Question? Oh, I agree. Oh, you agree, okay. It's just an intuition for thinking about appending two lists. I take the first list, I'm replacing cons with cons and nil with the other lists. They're now appended. So now that you know that, you should not be afraid when you see the code to append two lists. Here they are, list one and list two. I'm going to go through these lists here and replace cons with cons, that is to say, leave it alone and I'm gonna pick up this entire list two and smash it straight over the nil. And that will be appended. Cons with cons and nil with list two. So here is the code. Go in list one, replace cons with cons and nil with list two. This will append list one and list two. Sometimes I show people this code and they get scared. Whoa, hang on, what's going on here? I'm used to loops and things, that's how you append lists. Or go to the pointer at the end and update it to the other list or something crazy like that. But if you get an intuition for fold right, which is doing constructor replacement, it's pretty straightforward, right? Cons with cons and nil with list two. Of course it's going to append the two lists. This is just a point free form. You might choose to say that at your next job interview. Hey man, append two lists, okay. Flip fold right cons. Tell me how it goes. What about mapping a function on a list? So who's heard of the map function? Well who's never heard of it? How about that? Who's never heard of the map function? Everyone's heard of the map function. We have a list and for each of the elements I want to run a function on that element to make a new list. Like I might have a list of numbers and I want to add 10 to all of the numbers. I want to map plus 10 on that list. So here's my list. Cons a, cons b, cons c, et cetera, et cetera. What do I want to replace cons with? Given the function f, do you agree that I want to say cons f of a, cons f of b, cons f of c and d and then nil. That's what map does. I want to replace cons with f and then cons and nil with nil. So given x, I want to call f then cons and nil with nil. This will map a function on a list, the function f. So there's the code. It's not that scary now is it? That's how you map a function on a list. We replace cons with this function and nil with nil. We have mapped the function on the list. Once I had to write mapping a function on a list in Java, this was a long time ago, 15 years ago, I didn't use fold write. This is just like footnote caution. If you use fold write in Java, what's going to happen? Say it loudly. Stack overflow. Yeah, this fold write is recursive. For every element in the list, it's building up a stack frame. So you can imagine my disappointment when I called fold write on the JVM with a list of like 10,000 numbers or whatever it was and it just said stack overflow, have a nice day. Because the JVM I used to use a long time ago was the IBM JVM. It did tackle optimization, but it didn't optimize this one. It wasn't in tail position. So yeah, I had to use a loop and it didn't work on infinite lists either. Had to make it a heap list. So I'm just letting you know that all of this sounds great, but if you run out the door right now and said, oh, I'm going to do it in Java, caution. Same is true for Python and C-sharp. I've tried it. Stack overflow. What came up yesterday was this little operator here. Function composition. Function composition is take two functions and glue them together and make a new function. So I'll give you a bit of an intuition for dot, for function composition. I read it from right to left. Call F and then call cons. So wherever we are in the list, somewhere in the cons cell, which means it has an element right next to it. Call F on that element and then do cons and replace nil with nil. Wonder what would happen if you said that in a job interview. I should try that. Someone will say, map a function on a list and they're waiting for me to say for loop. Okay, no, fold right. What about flattening a list of lists? So we have a list and each element is itself a list and we want to flatten it down. What am I going to replace cons with? Any ideas? Append. The function we just wrote. Go through each cons and replace it with the function that appends to lists and nil with nil. That will flatten the list of lists. Cons with append and nil with nil. We leave the nil alone. There's the code. Fold right, append, nil. Fold right does construct a replacement. Okay, filter's a little bit ugly. You know, who's never heard of the filter function? Never heard of it. Everyone's heard of it. We're talking about it outside right now. That's how, okay, all right, filter. We're gonna take a predicate and keep the elements that match that predicate. That's a bit tricky. What are we gonna replace cons with? We wanna take the head at that cons, the A or the B or the C or whatever. And we wanna check if it matches a predicate. And if it does, we're gonna cons that value back on again. But if it doesn't, we're just gonna leave it off. And then move on to the next cons cell. So we wanna say, given the element that I'm visiting, x. If it matches the predicate, then cons x. Otherwise, do nothing. ID, the identity function. And replace nil with nil. So if you ever see this code, you'll know that it's filtering a list. Replace cons with this and nil with nil. I happen to have a particular aversion to the if-then-else construct, by the way. I wish it would die. It takes three arguments for a start, right? This one, this one, and this one. And for those of you who attended yesterday, what are my favorite functions? How many arguments do they take? One. So I don't like that one. There is a function that does if-then-else that does take one argument. It's called bool. I've used it here. And it does if-then-else with the arguments around the right way. There is a right way. It says, if this, then this, else that. That takes one argument. The reason I like that function is because I can get down to that point there. And that point means I don't have to name as many identifiers. That's just my goal in life. It's not really the point. The point is that I can do that. I can look at this code and I can say, replace cons with this and nil with that. What is it going to do? It's going to filter the list on P, okay? I find this one quite interesting. So what this function does, is it takes an element A and a list of A and it returns the first element out of the list. It's the first element. But it could be nil. And if it's nil, return the other element that I passed in as an argument. Okay, so if this list is nil, return that. Otherwise, return the first element. What am I going to replace cons with? Any ideas? Const. Const the first argument. I agree. And nil, that value there. That's the thing that we're returning if nil, right? So given an entire list, if you ever see nil return that value, but if you see cons, then return the value that's sitting right at the head of that cons. That'll do exactly what our requirement is for this function. So given this list, I want to return A. That's the first element of that list. Here is a function that, given the A, and then the rest of the stuff after the cons, just return A. Replace cons with that. And replace nil with that default value that came in as an argument. That will do what it is we need to do. So there's the code. Who remembers writing head or yesterday in the workshop? We wrote head or, right? This is head or. And we did it with pattern matching and all of that. We could have just written this. Fold right, const or constant with that argument. Who remembers this function? Who's never seen this function in their life? One brave person at the back, a few people. We had quite a discussion about this function yesterday because this function gets rewritten over and over and over again in its different formats. How much time do I have? I'll show you an example. Who's written this kind of code? Go through a list. If you see null return null. If you don't return a list of values. Who's written this? Half of you are honest. And the other half are currently writing it right now. It is of this form. Given a list of maybe null a's, return a maybe null list of a's. It is of that structure. Who's written this? Go through a list and for each of those elements go through another list and run some function at the end. What have we done here? Oh, we just joined it all back up to a new list. Compute the Cartesian product. I've written that function. It is of the same form. Given a list of list of a's make a list of list of a's. It is of that same form. Here's another one. Who's written this function? I have. We all have. Go through a list of things that have apply and apply them all to one single value. For example, 99 and collect all the results. It is of the same form again. The form is given a list that takes x to a, a function, and returns a function x to list of a, and puts x through all of those functions and gets all the a's and collects them in a list. Those three bits of code looked like all different bits of code, right? But actually they're all the same bit of code. They're all this function. This function's often called sequence. If you ever come across it. I'm gonna write sequence using fold write. What do I wanna replace cons with? Here are all my f of a's. That's an f of a, that's an f of a, that's an f of a, that's an f of a. What am I replacing cons and nil with? It's pretty close. It's pretty close. It's also very close, yeah. You might even be right. Like you probably have the correct code in your head. It's just that you didn't say it. Yeah. So given a, which is the f of a, and b, which is the rest of the list after the cons, run flat map, as you said. This is what this code does. Run flat map x, flat map b to y. Cons x and y, and lift it all back out again. I'm gonna replace cons with that function. And nil with, so the nil needs to be an f of list, right? Because remember we're returning an f of list. So I'm gonna take a list, nil, and I'm gonna call return, and it's gonna lift it back up. Return means the neutral, the neutral effect. Okay, don't do anything. Just do something with nil. So here's the code. Replace cons with this thing. So put lift to cons all the way through there. So to sequence a list, we fold right replacing cons with lift to cons. And nil with return nil. If you find, I chose to give you this example because it's hard to communicate. But if you wanted to figure out why this works, you wanted to just sit down and figure it out, you would get a pen and a paper and you'd say, right, what am I replacing cons with? Exactly. Well, with that function, then we have to figure out what that function does. And when you've figured it all out, you'd find it does sequence. It does all of those things that I just showed you with loops. FoldR may work on an infinite list. So if I had the list from zero to infinity, and I said, call that head or function back here, where is it? This one. So here's a list to infinity, zero to infinity. And I said, okay, passing some number here like four. I should get back zero, right? Because that's the first element of the list, zero to infinity. Okay. You wanna see some code? This is an infinite list of ones. You might not believe me. In which case, do you believe me now? Fold right, const. So take, that's it. Okay. Head or 99 infinity. This will not go all the way to the right of that list. Because when it gets there, there's just one cons, it's all the way. And so I should get one, and I do. So fold right just worked on an infinite list. What's the complexity? Of head or, it's O, O, O one. Right, is that what you said? Head or should be O one. So whether or not fold right will work on an infinite list depends on the strictness of the function that we're replacing cons with. Okay, so const, the function I just used, is lazy. It ignores the second argument. And therefore it works on an infinite list. It only replaces nil if nil ever comes to exist. It doesn't exist in infinity. How about this function? Fold R cons nil. Leave the list alone. Replace cons with cons nil with nil. It does nothing to the list. It's an identity function. What's the identity function? Oh, what's the function that gives me an identity for bool? It's an interesting question. I just showed it to you. I'll let you think about that. So the key intuition is the thing to take away is a left fold does a loop and a right fold does construct a replacement. If you always remember those two things, you'll never go wrong. Left fold will never work on an infinite list. We can see that in the loop. Right folds might. And these are just independent observations. They've got nothing to do with programming languages. I've used Haskell as the example. But these are just independent things of the programming language. So we could solve all of these problems as we just did. I just want to be very, very clear on this. Fold left does a loop. Fold right does construct a replacement. And there are no footnotes required. This is precise. Okay. If I, you know, I don't want you to ring me up next week and say, oh, you told me it does construct a replacement. It didn't this time. Yes, it did. It always will. Okay. There's no footnotes required. Thanks. We've got time for a quick question or two. Cool. Hang just wait for the mic there. Yeah. The example that you had for sequence, right? Yep. Where you had a list of side effects. If you could go back to the slide. Sure. Yes. So you're applying A first and then you're calling it on B as well. Does that mean, would that work on an infinite list of side effects or if I just wanted to apply the first N side effects is that going to stop at N or is it going to completely traverse the list? It's a really good question. I don't know if I've got time to write the code but I'll just give you the answer. The answer is yes it will work on an infinite list and I'll give you the example. Suppose I had an infinite list of maybe values. Okay. Or so the nullable kind of value and we wanted to sequence them. And if we remember what it does, if it ever sees the empty or the null case then it just stops right away and returns null. So you can imagine that I had a not null value. Say let's say five of those and then a null value and then an infinite not null values. It should give me back null and it does. So yes it does do that. It will work on an infinite list. You look like you don't believe me so I think we're gonna have to go out there and write the code and that's okay. We'll do that. But yes it will, okay? Yeah, so it's easy to find out that where we should apply for lift because it's whenever we solve C loop or so we will apply the for lift but my question is how to get the intuition then when we should apply for right. For example, the examples you have given for for right it is append filter. So these methods are already there. We don't have to do for right for that. We can go and use filter and all these things append length of a list. So when should we apply for right? Means in real application. Yeah, it's a really good question because here's the best I can do which is to give you the red flags. Like I was trying to be precise so I didn't wanna give you the red flags because they're not quite precise. So let's talk about the length function and what's the length of the infinite list? And the answer to that is it doesn't fit inside integer and so we immediately suspect that maybe we should use a left fold, okay? And it turns out that yes we do. That won't always work. On the other hand let's append two lists. Suppose I had the list from infinity and I appended that to infinity then I said what's the first element? I should get an answer and so we're probably not going to use fold left in that case. So these are just red flags but they're not precise, okay? Does that help? I could write a different length function that doesn't return int. It returns something else, another data type into which infinity does fit and then I would use a fold right, okay? So you have to sort of pull all these details apart. Look at the red flags and figure it out from there. I can't give you, I can't think of anything that is very precise. It depends on strictness and I'd have to write big paragraphs and things. We can talk about it though more afterwards if you like. Yeah. I mentioned that fold left generally doesn't work or it doesn't work on infinite lists. That's right. But the function that we are passing, if we add that additional logic there, for example a take function which essentially takes an element and then a map on that or something like that. Do you mean like take the first few elements? Take first and apply F, right? Yeah. So why can't we use fold left there? It's essentially an implementation. To write take, you know? Yeah, a map and a take. So I'm gonna write the take function. Yeah. Yeah, I'm gonna use a left fold. If take, except an int. Right. So that's an infinite, I can do that on infinite list as well. Actually, yeah, no, sorry. I'm not gonna use a left fold. Yeah, I'm gonna use a right fold there. Yeah. But I'm gonna want strictness. Yeah. So the function, the natural support is with right but what I'm saying is we can have guards on the fold left function that we pass to maybe support take on left fold itself. So. For example, if the fold left says take 10 or int 10. Yeah. But so we're not gonna use fold left to implement that function. But I'm saying is we can. Oh, we can. Can we? The f that you're passing that should have that check in this case that you don't call the function anymore. Since it's stale recursive, you just. I don't think that'll work. I don't think you can write take just with a raw fold left. You'd have to do a few tricks. Yes. Yeah. We have to essentially not, it will not be a raw fold left. Yeah. Right. Okay. So the point you wanted to make was that it's a natural support for an infinite list or a stream list is, you should always fall back to fold rate. Yes. But fold left, it's not that it's not supported. You'd have to do a bit of tinkering with the function that you're applying. That's right. Yes. To do take, yeah. The take function is quite quirky actually. Yeah. There's one more there. So during the talk, I noted down this question and it's like, suppose we are finite list, not an infinite list. So in that case, why would I ever use a fold left when I have a simple loop? Or in general, like if I generalize this question, why are like loops forbidden in functional programming? Oh, why? Okay. I'll answer the second question and hopefully that'll answer your first question. Okay. Okay, so why are loops not allowed in functional programming? It's a really good question. Let's have a look at a loop. They're all the way back here, right? Got a way to go. Where was it? Geez, I got a long way to go. There's a loop. Why are loops not allowed in functional programming? By the definition of functional programming, anything that appears on the right side of equals, I can substitute with what's on the left. Okay, that's the definition of functional programming. And therefore, if I take say this loop here and I've said r equals zero, I can now go through this loop and substitute every time I see r with zero and the program should not change. But clearly it does. Okay, so if I replace r with zero here, this is a different program. And so it violates the rules of functional programming. So that's why I can't have loops in functional programming. And that's why we resort to four left and all right? Pardon? And that is the reason why we resort to things like four left? Yeah, well, it's a consequence of resorting to things like fold left. But you might say something like, the reason we use fold left is because all of the loops have been refactored so that all the differences are out as function arguments. And so then we're just gonna use fold left. Okay, and are there some performance differences also? Like for the similar list, small list, if I use four left versus if I use while loop, conceptually I understand, but is there some performance difference also? If you use a fold left versus a loop. Yeah, it's simply counting. It depends on the language, right? So there is no loop in Haskell. So there's nothing to compare to. But if you go and use say Java, then yeah, because you're gonna build up stack frames unless you do a tackle optimization. It depends on all of these kinds of questions. Yeah, okay, cool. All right, I think we're out of time. Thanks guys. Talk outside, do you like?