Distilled Functional Programming
What is functional programming? Sure, there are academic answers, but is there a good definition that encompasses all that we do in day-to-day software engineering? In my book, Grokking Simplicity, I gather functional programming practices from the industry, distill them down and teach them to beginners.
In this talk, I'll present functional programming as a set of skills, not a dogma about programming style. Then we'll get an overview of the three levels of functional programming and learn some practical skills you can apply at your work, regardless of the programming language or paradigm you use. You'll get a good sense of the style and scope of the book, and I'll present some sneak peeks at upcoming chapters.
Video
Slides
Transcript
Hello and welcome to closure mid cities and this is April 6, 2020 and we are in the heat of COVID-19 and coronavirus right so this time we are meeting virtual and this is I think working out well we may integrate some of these virtual components to more of our meetups going forward. First we are new with us, we are a meetup that is in the mid cities area of Texas so mid cities are the cities between Dallas and Fort Worth and so it's a growing community and so we're really excited to be talking about functional programming with an awesome speaker tonight and so I'll pass that over in just a moment but I wanted to go through a few slides first. So this meetup exists to help people explore the functional programming paradigm with closure so they can build simpler systems. So there's a lot of functional programming languages out there but I feel that closure can help us build those systems simpler and so that's kind of why we made this meetup and so if you are here I hope that you are interested in learning closure at some point. And so for the agenda tonight I wanted to just quickly go over our plan for 2020 kind of where we are in that regard and then, and then we'll jump into our presentation. It may start just a little bit before 7pm. Alright so for the plan for 2020 we need to establish some additional leaders right so right now I am the primary facilitator for these meetups which means that if I get sick or something happens, then then these meetups may not continue so if we can find some more people and you are in the mid cities area definitely reach out to me and then we can I can get you up to speed on some of the tech that we use. And then what you see here I'm queuing up a list of initial speakers we've already had some amazing speakers this year Jean Kim for one of the sessions. We've always got our local Michael Nygaard who's been a very present participant in these meetups and so it's been great working with him. And then but if you have ideas of people or topics that you'd like to hear definitely leave them in the comments of the YouTube channel and I'll catalog those we can queue up some additional speakers from there. And then also this one's got a checkmark on it, establish the meetup channel on the Algerian slack. So what you've got to do if you want to join the Algerian slack is go to luxurians.net so CLO. J-R-I-A-N-S.net right and then and then you can request an invitation we're in the mid cities meetup channel. All right, so we're going to jump right into our presentation for tonight. So we've got the amazing Eric Norman. And so if you don't know him which you should totally. But Eric Norman is a functional programming teacher writer and consultant. And you can find him teaching functional programming on purelyfunctional.tv and lispcast.com. And so he is the author of rocking simplicity published by Manning. And he lived in New Orleans where he was raised. So what I'm going to do is I'm going to go ahead and tap it over to him. Hey Eric. Hello. How are you? Hey, doing good. Oh, I'm pretty good. Yeah, great. Awesome. Thanks for having me here. Right, absolutely. So I'm going to transition the screen over to yours. And whenever you are ready, you are good to go. All right, thanks John. I want to thank everyone for coming. How many people do we have? Curious. Is it like handful 20? Yeah, yeah, yeah. Right now we've got about 22. 22? Okay, cool. Great. Well, I'll get started. I called this talk a theory of functional programming. Mainly because I feel like the definition of functional programming that we find online. Textbooks and things is largely focused on the academic side. You know, functional programming was kind of quarantined, if you will, in academia. And for a long time. And so that's where most of the work happened. And now that it's sort of escaped into industry, we don't have a good definition for what it means in an industrial context. And so I feel like I just by chance like found a good theory that explains things and started talking about it, started writing about it. And then I started writing a book about it. So I'm writing a book. Why don't I switch my slides here? The book is called Grocking Simplicity. There is a link up here. Oops. I don't know what happened. Okay, there we go. There's a link up at the top. And that'll take you to the page where you can buy it. And if you use this code here, this TS simplicity, you can get 50% off. And it's in early access, so you can't get the whole book yet. But if you buy it, or even if you buy the print book, when it is printed, you'll eventually like get a surprise in the mail when it's done. And so I'm going to give a lot of the stuff is coming straight from the book, and then some of it's like hasn't been published yet. It's like stuff I'm working on or stuff that is just kind of in the queue that hasn't been published yet. So it's a little preview here. Okay, so I had this issue to deal with. What is functional programming? And I kind of skirt the question and because, you know, it's actually a really hard thing to define in a way that everyone will be happy. And I thought about picking a fight and like, you know, fighting with people who, you know, a lot of what people say about functional programming is something like it's programming with pure functions. Period, end of story, no discussion left. And I don't like that because I know as a functional programmer, I don't just use pure functions. And so it doesn't quite capture what I do. And what I know other people do. So I'm trying to, I'm going to skirt the question and just say, it's a set of skills. It's a set of skills that you would more likely find in a functional programmer than in an object oriented programmer or a procedural programmer. I feel like that's a pretty, excuse me, a pretty good way of getting around. And so then I just have to teach a bunch of skills and these skills should be useful for functional programming, but also in other programming paradigms. So that's what the book is about. Another question that I think needs answering is why is functional programming even a thing now. It's very old paradigm. You know, LISP goes back to 1958. But why is it that only now do we see functional programming even, you know, something that you can get a job in. I'm talking about it on blogs and things. And the more I think about it, the more I realize that it's really because of distributed systems. All the systems we write these days are distributed. You're writing a mobile app. Well, it's got to talk to the server. And then even on the server, there's like 20 servers because it's in the cloud. And there's the databases that it's talking to. And there's the APIs it's calling out to that are on different machines. So like we do so much that's distributed. And the object-oriented model just doesn't ask the right questions of distributed systems. Whereas the functional programs might not have all the answers, but we're asking the questions. What happens if that times out or what happens if I get to, you know, what if what if I send the email and then I don't get a response like what do I do. Functional programmers ask those questions. So, and we have some answers. So that's why functional programming is gaining popularity. So I've taken the skills. I mean, functional programming is huge. I cannot possibly put it all into one book. So what I've done is I've picked cherry picked like skills that I think are important and foundational and very useful in a industrial application. And after, you know, figuring, trying different ways of organizing them, I found this thing that is pretty satisfying to me that there's three levels. Like you can, you can get a lot of value by just doing one level and then you get more value by doing the next level totally, you know, it's not necessary that you learn all three before you can start doing functional programming. But you learn one level and then you advance to the next level and advance to the next level, and they kind of build on each other. So this first level is distinguishing actions, calculations and data. We're going to go into that first. We're going to go into all three of these levels. But they correspond to the three parts of my book, and I've actually finished this first part. So I actually can, I actually know everything I'm going to say, which is kind of, is kind of cool. I know everything that I wanted to say in this part. The second one and the third one. I know much more of vague idea of what I'm going to say. So I expect, I expect a lot of questions. I'm happy to answer anything. All right, so let's go into part one. I go into, there's actually seven chapters, eight chapters. No, nine chapters in part one. And each one deals with a different skill, but I'm just in this presentation. I'm just going to go over these four skills. So the first one is, is knowing actions, calculations and data, being able to recognize them in your code. I feel like a lot of books kind of assume that you can already do this so that it's going to be really simple, really easy for you to do, and just pick up. They'll just say, Oh, well, we'll get into it when I get into it. So these are the four things we're going to go into in the presentation. So imagine we have these little snippets of code that we've taken from some code base. We got this like, Oh, and by the way, the book is not enclosure. I wanted it to have a wider audience. So I chose JavaScript and JavaScript is actually a pretty good language for teaching functional programming. And one of the reasons is because it's not that good for functional programming, oddly enough. So that means that anything that you have to teach in it is a little bit of friction. So it's, it doesn't feel like, Oh, this language is this language or this language feature is required to do functional programming. For instance, if I used Haskell, you know, there would be, it would be easy to say like, Oh, well, everything's pure in Haskell. So you need a pure language to be able to do functional programming. And we know that's not true. Okay. So it's, it's actually nice. JavaScript has first class functions. It has a decent set of data structures. And so you can do quite a lot, but it takes discipline. Okay. So this top thing we have is just like a piece of JSON, just a JavaScript object. There's this line of code that looks like it's sending an email. There's this one that's summing some numbers. This one is sending, saving a data to the database. This one's calculating the string, the length of a string. This one's getting the current time. And this one is just an array of numbers. So the first thing we can do is we noticed that, well, I did have stars. There's some of them have stars. Right. These are different from the others because you don't really want to send that email twice. Right. You, you have to be kind of careful calling this one. Whereas if you sum numbers twice, sure you're wasting, you're wasting some cycles, but like no one's going to get angry. Same for saving the user to the database. Like if you save it twice, that could have some effect. It could overwrite data in another way. Like, so you have to be careful calling these ones with the stars. Get current time. If you call it now, it's different from calling it in an hour. Right. You're going to get a different answer. So we're going to draw a line here and just put all the ones with the stars above the line. All these ones that you got to be careful how many times you call them or when you call them. We're going to call those actions. And then so everything else below the line, these things don't depend on when they're called. This list of numbers is going to be the same forever. And likewise, if we sum them up, that sum is going to be the same forever. It doesn't matter when we call it or even how many times we call it. But there's some difference between having a JavaScript object and having a function that we're calling. Right. There's some qualitative difference. And so we want to draw another line and put the things that are actually executing code. You call those calculations. Those are computations from inputs to outputs. And then the data, which is very inert. It's just facts about events. And then, of course, actions are these things that depend on when they're called. So these are the three main or the three categories that everything falls into in functional programming. And this is kind of the basis of the theory I was talking about. One thing, this is a closure audience. So I feel like I can talk a little bit deeper about functional programming. Y'all already do functional programming. When we talk about the kind of standard existing definition, I'll call it the academic definition of functional programming. It's just about these bottom two. And then somehow they try to make actions. Like disappear. Right. Like, you know, in Haskell, you'll, you'll use the IO type. And you know, you can wonder like, well, when does the email actually get sent? Right. Like, it's not in my code because my code is just building up this IO object, which is a pure immutable value. But where does it actually get called? Right. So there's a little bit of sweeping under the rug in academia. Just a little bit. But I think the more pernicious thing is just to kind of deny that doing anything in actions can be functional programming. I've heard people say, well, if you're sending emails, that is not functional programming, you're into procedural code again. So that means in Haskell, if you're doing anything in IO, oh, that's just procedural. Right. Everything else is functional, but that's procedural. And I think that what the reason I don't like that is I think that functional programmers have a lot of good stuff to say about actions that other paradigms aren't saying. For instance, how can you make actions safer? You know, how can I make it so I can call send email twice? And it doesn't actually send the email twice. Right. That's called item potent. Right. And so we have terminology for it. We have a lot of interesting things to say. In closure, we have mutable state that is an action, right? An atom. You can change it over time. So it does depend on like when you read it, it could be a different value. If you read it now versus reading it later, but we've kind of made it much safer. It has certain properties to it, mathematical properties that let it let's it be a lot easier to work with. And so we do have a lot to say about actions. So I want to make it like, you know, at the same level as the other two. And, you know, calculations are the functions that are boring enough that you can, you know, analyze statically. Right. If I put it like that, like, they're less interesting. The actions are the more interesting things. All right. So, yeah, we're going to be going through actions, calculations and these are just to summarize stuff I've already said. So actions. I looked it up in a dictionary. Got to do that. The process of doing something typically to achieve an aim. Okay. These are typically in, you know, in our circles called effects or side effects. I didn't like the term effect because if you have a cause and an effect, like the effect is the email being sent. The cause is you called that function. That's that actually sends it. And I want the, I want to talk about the function itself. Not the calling of the function and not the email being sent, but the function as a thing. And so I had to come up with a new term and I'm calling them actions. And maybe one day I'll regret it, but I'm not talking about effects. I'm talking about the action, the function itself. So it's actually more proper to call it an impure function. An action is an impure function. And so there's a rule of thumb, you know, where you draw the line is if you run them or it depends on when you run them or how many times you run them. So anything that it's kind of timely, right, how many times or what time you run them. Okay, calculations. This one is just computation from inputs to outputs. We typically use functions to inputs or the arguments. The output is the return value. We'll call them pure functions. I'll just call them calculations in this talk. And then these are eternal. They're outside of time. The plus function is always going to be the same, like it's not going to change if you call it twice. We could also call them referentially transparent. Okay, and then data. This one, you know, what I'm learning is that the concepts that people find easiest are the ones that are actually the hardest to make people realize like how deep it goes. Like because data. Oh, that's just some numbers or something. No, it's actually facts about events. And then they can be used as a basis for reasoning discussion or calculation. So this facts about events, something happened. We record some data, some fact about it. So you have some input device, like a keyboard and you record, they hit the F key, right, that is data, and then that can travel around your system. The characteristics of data that make it interesting is it's inert, like it doesn't run. It is pretty transparent. It's serializable because it is not, you know, some kind of machine code or something that function would require like it. You don't know what it's going to do until you run it. But the flip side of that is it requires interpretation. Right, so you can't, you know, if you have, if you have a piece of data, you have to have a program or a person to read the data and, and to use it, right, it can't just like run it. All right. So we're going to talk about the spreading rule. This is another, like, thing that a lot of people stumble on when they're learning functional programming. So here we have a programmer. She's learning functional programming. And she's got this code. This is her code. It's got a main function here at the bottom. And that just calls affiliate payout, affiliate payout loops through all the affiliates and calls, figure payout and figure payout determines if they're owed more than $100. And if they are, then it sends them a bank pay, you know, transaction, and with the amount that's owed to them. And so she says, well, this is the only line that has an action on it. Obviously, we don't want to send the same payout twice. It's an action, but this is, it's pretty functional code because it only has one action. But she's not taking into account the spreading rule. So the spreading rule is pretty easy. If you have a lot, let's, let's look at it like this. So here's the same code. So this is the only action, or this is a known action, right? So we'll highlight it. And then that means by the spreading rule, you have to also highlight the function it belongs to. That is also an action. And because figure payout, let's see, figure payout is now an action. And you call to that and you have to highlight as well. And so that means by this, you know, continue the spreading rule, affiliate payout is also an action. And that means that this is an action. And so the whole, the whole thing is an action, right? And we know that we're closure programmers. We know this. But this is something that I've noticed people not being able to, not, not having internalized. They can't reason about this deeply embedded, you know, three stack frames down this, this thing being called. And that kind of infects everything above it on the stack. It's something that people, people need to learn. And somehow we, we know it. And there's just not talked about that much. So these are, these are all actions. You could call them all impure functions. Right. So now she realizes it. Okay. So I put this in here. This is like a screenshot from my book. The book does have like cartoons and it's trying to be very graphical like this. All right. Another skill that is in the book is taking this, this is an action. It's called Calc cart total takes a shopping cart. That's a global variable called shopping cart. And it here it is shopping cart. And it calculates the total and it stores it in another global variable shopping cart total. Okay. This, you know, I know functional programmers wouldn't have written this, but someone wrote it and now we're trying to analyze it as functional programmers. And so what we need to do is figure out where all the inputs and outputs to this function are. So I've underlined all the outputs and inputs. So we're writing to this global variable. That's an output. We're reading this global variable. That's an input. This is also an input we're reading here. Then we're doing some DOM manipulation. So that's an output. We're updating more DOM with the icons. That's an output. And then we're updating the DOM over here. So we've, we've kind of figured out all the inputs and outputs. Oh, right. Probably should have done on this one. This is cleaner. Let me do it again. So we got this output input output. This is a lot simpler. It doesn't have the DOM stuff in it. So what do we do with this? Well, this is the function that we started with, this count cart total. We're going to replace this global variable. Just use a local. So instead of initializing it to zero, we'll use the local. We'll modify the local, just like we were modifying the global here. So because it's local, no one else can see it outside of this scope. And so it's not, that doesn't make this an action, right? So then we just return the total. So now we've gotten this value out of the function. It has no other inputs and outputs. Well, it has the shopping cart still. Okay, I'll go over that. So we're just eliminating this one. So we're eliminating this one output. And so then we have to then in the thing that calls it. Use the return value and assign. So notice we're just moving the assignment from basically here to here. Like you still need to assign it, right? Like this, the global state still needs to happen. We have, you know, we're doing a small refactoring step by step. But we have made it just a little bit. This is now a little bit more pure, right? And so the next step you could imagine is that this input, the shopping cart length, because it's an input, it becomes an argument, right? So we've taken the output and turned it into a return value, and we've taken these implicit inputs, turn them into explicit inputs, which are the arguments. Okay, so that's a skill we go over in the book. It's probably the kind of thing that as closure programmers were used to doing. But I wanted to show like the nitty gritty to people who aren't used to it. Another skill we look at is immutability. JavaScript does not have immutable data structures. So we have to do it by discipline. And one of the disciplines is called copy on right. It's pretty simple. So we have this array dot shift, which modifies array. And so if we modify it, like it's no longer immutable. So what we need to do is make a copy. Then we can modify the copy. So before anyone has seen this copy, it hasn't escaped the scope. And then we return the copy. Right. So this drop first on this side, this copy on right side. Now is implementing a copy on right discipline. And so what I suggest in the book is that we go through all the array operations that we're used to. And we wrap them up in these functions that implement copy on right. And so then we have a library of copy on right operations that we can use for everything we need to. So here are the rules. Again, number one, we're going to make a copy, modify the copy, return the copy enclosure. Of course, this is all happening in closure. Because it's copy on right. The thing that we have is that they are implement. It's all done for us like all the standard library does this for us. It also makes it because all of them are implemented as persistent data structures. They you don't have to copy everything. Right. You can copy a sub sub structure. And it'll share the structure with it. So it makes it much more efficient. Except I do have to say that usually what we're doing here, I can talk about this because we understand as functional programmers. We're making shallow copies and making shallow copies of small data structures is not expensive at all. So, I mean, in modern computers and stuff. You don't want to do it willy nilly, but people are doing it more and more without even realizing it. For instance, like the spread operator, they're like these structuring and restructuring in every function call. I see it with all the ES six going around. And they don't realize that they're making copies already. So why not just do it to enforce this discipline. Okay. And then we have a second discipline. Copy on right is great if everyone's doing it. Right. If all your code is doing copy on right. Nobody's modifying any of your data structures. You're, you're good. Right. But that's often not enough. Often you have an API that you have to call some library and that library does not implement copy on right. You don't trust that it does at least. Or you have some legacy code. You got to call. How do you deal with it? Well, or you're writing a library. And so you get a data structure from the outside. You get some JavaScript object or an array. It's mutable. You don't trust that they're not going to modify this after they pass it to you. So what do you do? So in the case where. Okay. So I'm, let me, let me explain this diagram. So I've got these two concentric circles. The outer circle is the untrusted code. So this is code like, let's call it the legacy system that was written without copy on right. It mutates all over the place. And then inside you have this safe zone, which is all the places where you have implemented immutability. That's the safe zone. So you have this data from this is the original data. That's what the O is. You have this data that is mutable. You have to consider it mutable. Even if you don't read the code, you don't know if it actually does mutate it, but you can't trust it. What do you do? So if it's going to be passed to you, let's say you're writing a library, what do you do? You, they still might have a reference. So you have to make a copy immediately. And you have to make a deep copy because you can't trust that any level of the nested data is not referred to somewhere in the untrusted code. So you make a deep copy and you just discard the original. See, I don't need it anymore. I've got my own copy. And then you can do your copy on right inside your safe zone and you're fine, right? The next, if there's any questions about that, feel free. John says he'll stop me if I need to answer a question or something. Yeah, no questions about this yet. Okay. Let me see. What are the, what's the question? Yeah, I mean, there's no question yet about the concentric circles. There was a question that came in earlier. Back when you were talking more category theory type stuff, I can read that question if you're interested in that one. Or you can put it on the end. Let's save that for later because it's not that related to this. Yeah. Okay. And we do get into that kind of near the end. Okay. So the opposite situation where you have some immutable data in your safe zone, but you need to call some code that's in the untrusted code zone. What do you do? Well, you don't want your original to get out because they'll just walk all over it and change, change it will and nilly. So you make a deep copy and then you pass them the copy. Right. So you just pass the copy and you, you throw, you don't have a reference to the copy. Just let it go. Unless you need it because, you know, you need to know, you know, some, some protocols are like, okay, pass me an empty array. I'll fill it up for you. You know, and then you can read from it. Okay, if that's the case, you need to keep a reference to it. But you just, you want to protect this original. Okay. So there's really two rules. It's, you make a deep copy as the data leaves, the safe zone, and you make a deep copy as data enters the safe zone. Now, notice this is exactly what happens when we use service oriented architecture, microservices. So my system needs to send this other system, this other service, some data. I serialize it to something like JSON. That serialization is a copy. And so now they're going to read in the JSON. It's a, it's an identical copy. It's a deep copy. And then, you know, I don't care what they do with it, right, because it's a different service. It doesn't share memory. And likewise, when they send me data, I know I don't have to worry about them being able to change it because it's, it's, it's been serialized, right? It's just like a message and I created a new in memory representation of whatever stream I got. So this is another, another argument for the efficiency of this. We're doing it all the time. We're making deep copies of things. And so I just want to, I just want to leave that there because it's, it's often the thing that people have trouble with. I think this is super expensive, but it's way less expensive to make a deep copy in your own memory than it is to serialize it over a network and then deserialize it. Okay, so that's all I wanted to talk about in part one. Each part ends in a design sort of capstone chapter. And so part one ends in stratified design. And, I'm not going to go into stratified design. It's like, it's like a whole thing by itself. But it's, it's a, I just want to talk about the, the, we do after going through all these skills, we do talk about design, which I think is important because there isn't much about functional programming and design. Okay, John, question. Sure. Yeah. Okay, so I'm going to pop it up on the screen as well. So Ian Fernandez asks, how does social make the copy faster? Okay. Yeah, that's a good question. So, if I need to make a copy of an array in JavaScript, let's say it has 10 million elements in it. This is 10 million numbers, right? I need to make a new array of 10 million numbers and then run through the array and copy each one to the, to the copy, right? In closure, when I make a copy, because the, the vector is the equivalent of the array, the vector is not really a linear array. It's actually a tree. It's actually a tree structure. So if I change one thing in it, I don't have to copy the whole tree structure. I only have to copy the node where that number is stored, the one that's changing. Plus everything up the tree, because that thing is copied. So now I need a thing that points to the new copy, and then that, so that's a new thing. So I need a thing that points to new. But everything else is untouched. It's, it's shareable. You know, it's, it's still immutable and it's still the same value. So it really saves, it's faster because it's just doing less copying. It's doing less transferring. And you see that more and more like the, the savings as the data structures get bigger, as you have a billion things in one array. Closure can just change a few pointers, copy a few small objects, you know, that have, you know, maybe, it would have to change like at most seven objects with like 12 pointers in each one. Awesome. So, and I couldn't probably already answer this, but there's a final question. How does closure handle the city of the city without consuming too much RAM? Yeah, so it's the same answer. It makes it faster in terms of processing, because you actually have to load less into the cache. And, you know, I guess it also doesn't have to loop through the whole array, which would, it's significant as well. But it also doesn't have to copy as much. So you can share a lot of the structure between the two vectors. So that uses less RAM, because you're sharing a lot. And, and the bigger the data structure gets, the more you're sharing. Awesome. There's another question. All right. So, you can talk to your apps. What is the minimal set of features you think language needs to have for functional programming? This is a really good question. And I, I want to put it like this. Each level brings with it new requirements. So, in part one, you need some way of identifying the things that will change stuff. Right. So like if you're an assembly, every assembly instruction changes memory. Right. It's going to change a register. It's going to store it in in RAM. Like there's some something is changed. And so it becomes really hard to start doing functional programming. You have to build up all the constructs, like, you know, using local variables and storing, you know, going in and out of local variables when you're calling functions. So you could say having some kind of lexical scope on your functions is required for level one. Right. So functions and lexical scope. Maybe. Just so that you could have something, some piece of, you know, object that you own. Right. Probably garbage collection is required. Some kind of like, I don't have to worry about memory management. Someone else is taking care of it. You know, I don't mean garbage collection like it has to be, you know, it could be reference counting. It's that's possible too. For part two, which we're going to get into where we're getting into first class abstractions, you need first class functions. Right. But I want to emphasize, you can do part one. You can do part one and get a lot of value out of it. Probably the most value in there is just being able to say that is an action. We got to be careful with that. That, and, and, and a way of saying, well, what can we take out of that so that we can have a calculation that we don't have to be so careful about. And then for part three, I think you just need good data structures. You just need a way of. Of making data in interesting, interesting patterns. There's another question for clarification on the copy type stuff. All right. So, Julian Sanchez says, the company you're talking about when you're only moving on to memory references, shallow copying. But when it comes to boot copying, how isn't that expensive on your data structures? So, deep copying is way more expensive than shallow copying. And it gets more expensive, the bigger the data structure is. You know, in a deep copy, you copy every level of the nesting, everything, all the way down to like the primitive types, like numbers and whatever. So, it's way more expensive, which is why I recommend creating a safe zone where you can use copy on right, which only requires shallow copies. And then when you're dealing with the legacy code that you don't trust or the API calls, the libraries, that's where you at that border from your safe zone, you can make the copies going in and out, because it is more expensive. The argument, though, that I was trying to make is that we do this already, like we, when you have a web server that is talking to a database, like we are copying data from the web server's memory into the database in some kind of serialized form. Like we're already, we're already doing this all the time. The thing you want to avoid is doing it for like everything. So every, you know, every time you add a new key value pair to your hash map, you don't want to make a deep copy. Right. That's for sure. But we're already making, we're already making copies at borders between systems, between the, you know, browser and the web server, we're serializing JSON back and forth. Those are all copies. So we just have to recognize that it's, it's already being done. Like we're, we're, we're, I'm only suggesting doing it at other borders, like recognizing that we can have other borders within our systems. Awesome. Thanks. I think you're good to go. Okay. So part two. Part two is, I imagine these levels of these three levels that I've got that correspond to the parts of the book. They're kind of like doorways or gateways like once you get the idea of first class abstractions first class functions. Like, what does that open up? Like what skills become available. And so that's what we're going to talk about these, these five skills. They're all very related. The first three are mostly pure things, mostly, meaning calculations. And then the second, the last two are going to be definitely actions. All right. So one thing that I've noticed functional programmers do that other. Other paradigm programmers need a better word for that non functional programmers do is they'll make a lot of functions like this. So they'll have a function called set price by name. And I mean, it's a pretty simple function. It grabs the item. This is a cart, right? It's setting the price of an item in the cart, given its name. So it takes the cart, the name of the item and the price to set it. So it grabs the item out. We're going to do this immutably. So that's what this is a copy on right version of mutating an object. So we're going to set the items price to this price argument that was passed in. Then we're going to take that updated item and add it to the cart. Okay. And then we have this other function called set quantity by name that does basically the same thing except it doesn't modify the price. It modifies the quantity. And then we have another one called set discount by name, which doesn't modify the price or the quantity. It modifies the discount. And if you look closely, you'll see that the argument, it's kind of like an argument. It's part of the name, though. Right? That we're just putting hard coding this string in, which corresponds to the name of the function, this piece of the name. Like, we, as functional programmers, probably like instantly see that. Like, why are you putting it in the name? It should be an argument because these functions are all implemented almost identically. So that's one of the first skills I teach in this part is just to recognize that having it, oh wait, having it, having what should be an argument as part of the name, like you should pass that in. The argument against it is now this is some string that, you know, people would call a magic string that you have to pass in. But, you know, we have type systems, we have dynamic runtime checks. Like, there's, there's ways of dealing with that. But the cost of having three versions of the same function is very high. Here, we can just check that the field is a known string. Okay, so, and that's a, that's like a, you know, it's not first class function yet. It's just a first class string, first class field name that I think is very common in functional programming, but we just don't see it outside that much. Maybe it's increasing, but, you know, if you go to it, the Java world, like, you definitely don't see this kind of thing because they don't have an easy way of, they don't have an easy way of accessing, like they don't use hash maps everywhere. They have methods with getters. Okay, so then the second one. Second kind of refactoring that we're going to do. Like, just imagine we have this for loop here. This is about eating your food. So you have a list of foods. You're doing these actions on them. You're cooking the food, then you're eating it. You're just looping through in the standard for loop. And then after we eat, we, of course, have to wash our dishes. So we loop through all the dishes. I'm going to wash them, dry them, put them away. But we noticed that this part at the beginning and this part are basically the same. But traditionally, you can't just separate this first part from this part. Like, when I was taught procedural abstraction, meaning like, how do you take a multi step function and break those steps out into their own functions, right? So like subroutines. You know, the easy case is like, well, just split the function in half and these first three steps, I'm going to put it into this subroutine and they call it by name. And then the last three steps, I'm going to put it into another function and call it by name. And you would have to always cut it sort of, you know, top and bottom, right? You couldn't cut out the middle. But here we need to cut out the middle because you can't really separate the for loop beginning or the opening braces from the end brace syntactically, it's not legal. I can't just cut it right here. You know, I can't cut it right here and then have maybe three parts like, so what I want to do is something like this. I want to cut it into a before part. This part, the body, we can call it and then the after. So this is like three steps, right? The red step, the green step within the other red step, but you can't do that, because you can't separate the syntactically, these braces. But because we have first class functions, we can take that green part and pass it in. We can wrap it in a function, F, pass it in. Right. So now we can call for each foods. And then have a first class function call that that we pass in here that does the two things, and then that eats it cooks it and eats it and then do the same for the dishes we wash dry and put away. Right. So I know like preaching to the choir here, your closure programmers, this seems pretty basic, but I feel like this is one of those abstractions refactoring that we take for granted. We do it all the time, and I'm trying to distill it into like some form that people can appreciate. This is actually really this refactoring of saying like, let's replace the body with a callback. This works with the copy on right. If I skip back for a second, see if I can do that quickly. No, I'm going forward. Let's get back. So here's the copy on right. Notice we're doing an array copy. And actually, I know that array copy doesn't exist, but just ignore that. Just pretend like that exists. So we're doing this array copy first. We're doing some modification, which will change every time, you know, that's the body, and then we're doing the returning the copy. That's the after. We have the before the body and the after. So this refactoring can give us a generic copy on right function that just takes this body, this whatever modification function you want to pass in, right, which kind of frees us again and makes it more efficient. We don't have to do a single, a single operation. We can do multiple operations in that function and save copies, right, because we know it hasn't escaped that scope. Okay. If there's questions about that, I'm happy to answer them, but I feel like this is something that closure programmers should already know about. Okay, so also closure programmers probably familiar map filter reduce. So, not going to go into it too much, but it's very easy to go from for each to map filter and reduce. So I want to talk about chaining. It's another, it's another thing where people might know that map filter and reduce exist in JavaScript or whatever language they happen to program in, but they're, they will sprinkle them here and there, but they don't really know the power of chaining them up of making like your whole function is just a series of these map filters and reduces. So that's what I'm trying to show here. So we have this for loop. We have some data, some variables we have to initialize. We're trying to find the average order from good customers. So good customer means they've purchased more than five times. And we have to get all the purchases, sum up the total for each purchase and then divide the sum by the count. Right. This code to me is like typical procedural code. It works is good clean. But we can do better. So here's what I mean by chaining. Well, we can define the good customers as you take all the customers and we filter them, keeping only the ones that have the purchase length greater than five. So more than five purchases. Then we can do a flat map. It's a variant on map that takes all those good customers and gets all their purchases. So this is going to be an array of all purchases from the good customers. Then we can map over that and just get the price out from the purchases because that's all we're, or the total. That's all we're concerned with. And then we can reduce over it. Just summing them up. So we're just passing in a first class version of plus. And then we can divide the sum by the length. And I'm not going to deal with the case where the length is zero. That's not my, it's not my fault that that's undefined. So, just to compare the two, I think that this one has so many gotchas. Notice we had to initialize these correctly. There's no initialization of any data at first, like we just, everything is just clearly this is what this variable means is what this variable means. Nothing has changed over time. Everything's a copy. It's a new thing. It makes a new array. We've gotten rid of that inner loop. We had nested loops here. And I feel like this simply reads more easily. I think people will consider this better code. And of course, it gets even better if you use like ES6 functions with the arrow functions because it becomes shorter. But I wanted to stick to this old school syntax. So, right, I'm working on the chapter for teaching this chaining piecewise. What are the little bitty skills that happen in this? Alright, so now we're getting into some more interesting stuff. Like I said near the beginning, when people talk about functional programming, they often talk about it. Like they downplay the role of actions. And I think that functional programmers are the ones who think the most about actions. So it's kind of ironic. Mostly they're trying to avoid them, but they know that sometimes they can't. So, like, let's imagine the situation where we have three different robots. They've horizontally scaled the cheese making process. So you'll have a robot that's just making dough, a robot that's just grading cheese, and another robot that makes the sauce and then finishes the pizza, right? Making the sauce takes a long time to cook. So typically, it finishes after the dough and the cheese are already ready. So this works most of the time. It works in all the tests. However, on busy nights and things, you know, there's a lot of chaos and turns out that it doesn't happen that way. So sometimes, you know, usually it happens that way, but sometimes it doesn't. Sometimes the make dough function finishes after the robot tried to roll out the dough, right? The sauce was made. It started rolling out the dough, and the dough wasn't ready. So, like, it just, like, didn't work, right? Who knows what it did, but the dough wasn't ready. The robot reached into the dough bowl and pulled out an empty thing. Okay, so in other cases, the great cheese happens after the cheese is supposed to be spread by the other robot. So what is this trying to show? Like, these robots are dumb. They don't coordinate. They should coordinate, but they don't know how to. They need to be explicitly programmed. They're just doing what they're with their program to do. And that's this is kind of trying to introduce this idea of timeline diagrams that I'm presenting in the book that these diagrams, you should be able to see, even from the first diagram, if you're reading it correctly, that this is a problem. You shouldn't have to stretch this thing out to see that. Like, your mind should be able to do that really quickly. And I feel like most functional programmers who've dealt with distributed systems know that there's no coordination between them. And so just because you think the sauce should be done later, doesn't mean that the dough will be already finished. And so this, you know, red flag should come up just immediately when you see this diagram. Uncoordinated, and you need, you need them to coordinate. So in functional programming, we, oh, just to just to be clear, you can actually enumerate all the different orderings of making dough grating cheese and making sauce. Because in a chaotic environment, these all might happen. And it turns out that only two orderings have the sauce being done last two out of six. All right, so if you take three operations happening in parallel, there are six possible ways they can, they can ordering orders they happen in. There's only two that work. So one third of them are wrong. And so we need a way of making 100% of them right. And so in functional programming, we can use some kind of higher order abstractions, some kind of thing that we can manipulate like a first class value or a first class state or something to help us. And in the book, I talk about this thing, I'm calling a cut. And I'm calling it a cut just because I want to make it very visual that you're cutting the timeline. You're saying, all of these robots, when they're done, whatever, however long it takes, we're going to make them wait for the other two. So when they're all done, then we can continue. Right. And if you have that guarantee, it doesn't matter what order these things happen in. It's going, this is going to be correct, the, you know, the, the assembly of the, of the pizza of the three ingredients is going to be correct. Because you really can't control when these things happen, when they finish, but what you can control is that nothing will continue until they're all done. Right. And that's a, that's a strong guarantee. It's enough to make a good pizza. Okay. So in the book, we talk about how to do that. You can do it with something like promise.all. But we, we make the abstraction, you know, by hand. And I think that that's a good exercise just to. I feel like as a closure programmer, I'm very, and, you know, lisp, it's very lispy. I'm so used to making my own things. I feel like it's a useful skill that you don't just say, what, what does my library give me. And I'll just use that. We often think through it ourselves and make it for ourselves because we will understand it. We will do what we needed to do. Okay. I'm going to wait for some questions because I'm finished with part two. Oh, I do want to say part two ends with a discussion of the onion architecture is the design capstone. Okay. I'll drink some water. Well, John, are there any questions? Yeah, we got a question, right. So. Okay. I know exactly what you mean in a language like JavaScript. Okay, let me put it this way. I think it's easier and closure because enclosure, we use the threading macros to do the chaining. And you can always just insert a line really easily and call whatever function you want. So you can just call like a print. Right. You can, there's a trick you can do to print. And it will print and then return the value. So you just put it like right in line and then delete it when you're done. Right. So it's just print line debugging. What happens in JavaScript is you have like a chain of four, you know, this dot map dot filter dot map dot reduce. And you feel like, okay, I need to know what's in this second step, like what is the second step returning. It's really hard to put in a print statement in there because you can't, there's no dot method on, on like a raise for printing. I suggest in using something like JavaScript that you do. Here's the slide. You do. There you do the chaining like with named variables. I don't think it looks good to have all these like dots dot dot dot. It's hard to indent. It's not always clear. I even wrote this one out. And I was like, oh, it's just so messed up. It's so nasty. So I named them. I just give them a name and then you can put prints wherever you want. So that's my advice. I agree. It's hard because you're operating at a higher level. You're operating over a raise of values instead of a single value. But that's my solution there. So does that mean that you don't prefer closures threading macro? Oh, in closure, I use it threading all the time. Yeah. I don't. I mean, I wouldn't do it with let's. You know, with a let. I would use threading for sure. Awesome. For sure. Great. All right. Those are all the questions that I see from that part. Go away. Yeah. Proctor has a good good comment that when you're using map filter and reduce, you're doing pure functions. So it is easy to test by its, you know, by itself that you know you don't have to set up a bunch of environment and things. I would not chain some, you know, actions like that. Okay. So part three. This. This is tough because I feel like a lot of this stuff that I'm doing in part three is is from my Haskell experience. And in Haskell, the language gives you a lot more. Let's call it gives you a lot more tools. The type system has the tools for describing your data and its operations. And closure makes it really nice to do parts one and two, right? Really easy. Part three. I feel like it's not that easy. You can do it, but it's the kind of thing like where I've been showing, well, in JavaScript, if you want to do a mutability, it's all on you. Like it's your discipline. It's up to your discipline. I feel like in part three is all up to your discipline. It's not perfect in Haskell, but it does have a lot more of the tools that you need. In closure, we tend to build stuff up in hash maps and just kind of leave it at that, like the data modeling is organic. You know, it's like, well, I needed this data. So I threw it in the hash map. And in part three, I'm suggesting that we do a little bit more design that we step back before dumping everything into a hash map and think about what we're trying to model, what are its properties. What operations we want to do on it. And what does that, how does that inform the data structures that we use. And, yeah, so this part, like I said, is not written yet, but I'm going to go over three, three ideas, three of the big ideas. Okay, also, this is, this is the, like, most advanced that I can see that is super universally applicable. It's not category theory, but there is a bit of algebra in it. I don't see category theory being super useful. Maybe that would be level four. Right. These actually start the most useful and become less and less. I mean, if you think about it, would you rather be able to do map filter and reduce or have immutable data. I would rather have immutable data. Right. That's more useful to me. So, even though it seems like oh map filter and reduce and the standard, the closure standard library. That's, that's where all the power is. I feel like it wouldn't, it wouldn't be possible. It wouldn't be as useful without the immutability. So, in the same way I feel like this data modeling is like, if you're really looking for where do I go next. A lot of people get stuck in part two, especially in the closure community. I don't mean anything against the closure community by saying that, but a lot of people say functional programming is just all about data transformation pipelines, which is just changing map filter and reduce. This stuff is where they could be going. There just isn't much talk. There isn't much said about it. Much written about it. And the stuff that is written about it tends to be in stuff like the Haskell community. And it's couched in category theory terms. And I think it's just not accessible. There's a bunch of important ideas that are pre category theory. Have a touch of algebra, you know, item potants, associativity, commutativity, that we can, we can start to use right away. So I want to talk about data modeling a little bit. So there's a notion of some types and product types. And then there's combinatorial types. Those are like recursive structures like lists, lists are recursive, right? It's got a con cell that points to a value and another con cell. So those can have infinite. This can be infinitely long. But some type and a product type. Some type means when you look at the alternatives, each alternative adds to the total possible number of states that you can, that you can represent. So just as an example, a Boolean is a some type. It has a true value, a true case and a false case. So you add one and one. There's two cases. Right. Now, imagine you had something like a maybe type and then we don't have that enclosure, but we have nulls. So if you have a Boolean, it could also be null. So you're going to take the two, the true and false and you're going to add one, the null, the null case. So you actually have three cases. And I mean, in Java enclosure, you're actually adding the nil case to every single value. Right. So it's always one more possible values. Okay. And then a product type is where you have a tuple. So if I have a tuple of two booleans, that would be two times to four. If I have a tuple of a Boolean and let's say an integer. That is two billion, you know, approximately two billion possible values by having a true case for each integer value and the false case for each integer value. I'm actually multiplying it. Right. So I have four billion. Right. So that's a product type. And the reason this is important is it's important to think about the structure of the data that we're making that we can target any number of cases that we want to represent by multiplying and adding using a product type or a some type. Right. And there's, there gives us options. Right. So we can choose to make if we have seven cases, we can say, well, that's a three and a four. Right. Or it's a six and a one. Or maybe that six is a two times a three. Right. So there's different ways we can structure the data. And what we want to avoid is where we want seven cases, but we use a data structure that has eight cases. Because then we have this case that doesn't really fit. Right. And we need, we need to think about that. And I think some types and product types are kind of a way of seeing that. Okay, I hit, I have eight cases, but one of them shouldn't be how can I make a new data thing, a new piece of data. You could call it a type, but I'm not saying you need static typing, but some kind of way of representing the data that can only have those seven. All right. Let's go back to basics. This is becoming really popular. Now I put this in the book. It's in the first chapter, a second chapter. And someone was like, this is so obvious. Like, why would you even need to mention this? So I'm not sure if I, if this is important or not, it used to be important. Like in, if you were a Java programmer in the 90s or the early 2000s, you would just immediately, if you need to represent this pizza recipe. As in code, you would make classes. Right. And you have getters and setters and you would, you know, think of it. Maybe if you had a, you have a pepperoni pizza would be one class and a cheese pizza would be a different class. Right. And you would just have like a dot prepare method and a dot assemble method. You wouldn't have them as data. Now that we've basically we're passing JSON all over the place. We're much more used to having this serializable form of what in truth is a procedural way of making a pizza. This assembly, this preparation. These are steps that you take in order to make a pizza. But we're representing it as data. We're very used to doing this enclosure. But I think it's not quite clear enough that this is like a real, a real new skill representing procedural code as data. Now, why do we do that? Because data can be interpreted in multiple ways. If we represent this pizza recipe as a class. If we want to change the way to change what we do with that data, we have to add a new method to that class and all the related classes, all the sub classes and the parent class and all that we just need. And then all the code has to know about it. It's expanding the API surface. And if we document it, it's like, it's like a thing. We have to do it some official way that like is useful for everybody. But if we just put it in data, there's a million things we could do with this. We can query it. Like let's say we have a thousand recipes for different kinds of pizzas. We can say, well, what pizzas have cheese. Right, we could look at the ingredients. Off the top of my head, we can say what pizza, well, yeah, what pizza recipes use slicing for preparation. So we're looking ahead and deep in here. We're going to look through all the preparation steps, all the ingredients. Do any of them have an action for a slice? So this is a way we can query this. But we can also say, well, how much flour do I need if I'm going to make a hundred pepperoni pizzas? This is another way of interpreting this data as like this recipe is an ingredient list, right? It's not a set of steps. It's something else. So this is the advantage of going all the way down to data. It's inert. It doesn't run by itself. Some robot has to read these little JSON objects and know how to interpret that to make a pizza. But that's only one way to interpret it. You can do other things with it. Okay. And so if we continue with this, if we continue with this idea, we eventually get to this idea, well, we're doing all this stuff with these ingredient lists. Why don't we refactor it into these functions? Like here's one function, ingredient list plus. It adds to ingredient lists. So just as a simple example, we have this one has one pepperoni and two, that's the quantity. It's like two pounds of cheese or something. And then three pounds of flour, right? And so the result would be this one. You add the things that are common, right? And then the ones that don't exist in both, you just copy them in. Easy. And you can imagine a, you can imagine a bunch of operations like this, plus one, there's a minus, there's times divide and split. So you're creating like this algebra, because they share what's called the closure property. Do I have? Oh, I don't have that. I thought I had a slide on it. So the closure property, if you notice, the argument for this operation is of the same type as the return value. Right. So it takes an ingredient list and it returns an ingredient list. And so the nice thing about that is we can use, we can recursively define expressions of pluses and minuses and times and divide and split. Arbitrally deep, because the return value of a plus can be used as the argument of a divide, right? Or the return value of a minus can be used as the argument of a plus. And so we can just make these really sophisticated. Algebra's algebraic expressions. So I would call this an algebra, because it has that closure property. And this is the kind of thing that I'd like to see more closure programmers get into. It's like, is find these little algebras, figure out their properties like list plus is is associative and commutative but list minus is is not, you know, like just figure those things out because those things are useful just thinking about how these expressions do fit together. How do they combine. Okay, and so another thing we can do with this. This is a kind of a different exercise is how do you model a Starbucks coffee. I use Starbucks because, you know, I think most people are familiar with this, they have all these options. There's the kind of the sizes, the different kinds of roasting beans, the different additives that you add to the coffee. We have all these different operations that we want to do to them. So we want to calculate the price is coffee, etc. How do we represent this. Well, if we're going to do it in JSON. We're going to want to do a JavaScript object. And this is a product type. Okay, so here's, here's the example that I should have given you before. So there's a few sizes that to choose from. So let's say there's three sizes and there's three different brews, decaf, medium and dark roast. So that means just with these two options up at the top. That's nine possible combinations. Right. It's three times three. Now we're getting into additions. Of course, we can add any number of additions. I mean, up until the size of the cup. Right. But this is now kind of throwing our, you know, there's nine and then in times infinity. And it's too many. But you could say, well, but what if I want to put two shots of soy milk and two sports of almond flavoring. So then you turn this into a hash map. And, you know, also in this case, does the order really matter of how I mix them and probably not. So we're going to use an unordered collection, the hash map. And, well, so that's, that's sort of the kind of thing that we, we do as functional programmers that I don't think is so commonly done. And I'd like to, to teach that. But then we need to model this editing process. So someone wants to make an app where you can order all these infinite coffees that are possible. And, but we need to let them do an undo and a redo. And we need to have, because we've already written code that uses that previous model that we just saw in the previous slide, this model. We need to be able to convert from this editing version to this version. Okay, so we can say, we'll just capture everything they do in the app. So they're going to set the size to vent. And then they change their mind. And they say, no, I want to go on day. That's too much caffeine. And then I'm going to add mocha. Oh, but I forgot that I like dark roast. And so I'm going to do that. So really these operations, the order on some of them matters. It doesn't matter. But what we want to do is capture everything, every setting that they change everything they set up. And then we're going to reduce over it. Wait, sorry, we're going to reduce over this to generate a data structure that looks like this. Right. So that is a kind of a ledger, like an accounting ledger. And that's what we get to in the design part of this third part. Like, how do you make ledgers because they capture the time, right? This is this order represents the time, the order that the user made certain UI manipulations. And so this is this first class notion of time that eventually turns into a coffee. Okay. I'll take questions. I'll put this slide up. This is where you can find me. I do blog occasionally. Mostly, I'm more active on my podcast right now because I can't write that much in a book and on a blog. I do video courses at purely functional.tv. I have a newsletter. It's mostly closure focused. And then you can find me on Twitter. Okay. Thanks a lot. So, yeah, there is a question. So I'll put that up on the screen. So Matthew, he asked, are there any research in distributed systems and algebraic effects. And is it possible to reason about effects interpret with different standards. Oh, that sounds like a research question to me. I, I'm not that familiar with, like, effect systems and, and how they, how they would work in a distributed system. Okay. I do know that monads are they model sequential processes. Right. So IO is a monad. And so you can do a step by step sequential thing and applicative functors represent things that can happen in parallel. So those are the two operations, you know, the two different ways of doing stuff, like either doing step by step, or you have your friend help you and you do them in parallel. So if you could have some system that use those two as its basic operations, then yeah, I think it's possible. I'm not that into that though. I, I guess I don't feel like I want some other system defining the possible combinations of actions for me. Like, I think it's cool that people are working on it that they're thinking about this. I think it's cool that there's a lot of research into this. And it certainly works. But I find that. I mean, it's going to, you know, it's going to sound bad. It's going to sound like I don't like, like some people. But for in my experience, using, say, the IO type as a monad in Haskell, really just encourages procedural programming. It doesn't encourage you to model. Say in in, if I can jump back to the slides for a second. In this recipe, notice that the preparation, these four things can happen in parallel, like the sauce and the dough don't really need to happen in any particular order. And so they're done in a hash map. Right. This is just Jason. This is all Jason gives you. It's hash maps and arrays. So like, you got to choose. It's either like order or no order. It's all you get really. But then the assembly does happen in a particular order. Right. Those things have to happen in that order. So I feel like this kind of flexibility of like just using data. Is is what I want. I don't want to like have to read somebody's paper and read the libraries to figure out. Is this even going to give me what I need? I would rather just write it up as my own data structure, not as some IO data that the Haskell runtime knows how to read and I don't. So there. Okay. Thanks. There's another question. All right. Daniel Craig asked, say that it was important to keep track of the steps in your coffee editing process. How could you add validation to make sure that the coffee was correct on a step by step basis? Any thoughts? Yeah. So at each step, let me switch back to it. At each step, as you capture an event from the user, right? And like I said before, data is facts about events. So this is a little piece of data that represents some event that the user generated. You're reading from the user's input. And you can validate at that point this reduction. You can do at any point to know. Do we have a valid coffee now? And does this operation also generate a valid copy? Right? So you can, you know, use that information to like disable buttons in the UI and and do whatever you need to do to keep the user from, you know, making an invalid coffee. You know, I mean, that's kind of a user interface question at point. How do you, how do you, how do you make that clear to the user? Yeah. Let's see. There was a question from early on. Let me see if I can find it. Okay. Here we go. All right. So Justin, hey, Jones asked questions, has Eric come across the Florida Pitten Library? It brings category theory, concepts, and closure for better or for worse question. I'm not. Yeah. I'm trying to think, you know, I write about a lot of libraries in the newsletter. So I don't think I'm familiar with it. I have seen some that do category theory. And what I've seen, I mean, these are usually from years ago, they try to model the Haskell way of doing things, which in Haskell, you attach the category theory concepts to the type using a type class. That's, that's how they do it in Haskell. And what I've seen in these other versions where they're trying to like say, this is how this is a monad. They're trying to use the type to define how the different, so like dispatch on the type like that might be a protocol or something. So they're trying to do something very similar to what Haskell does. But the type system enclosure, you know, the dynamic type system enclosure just doesn't have the features that that Haskell's type system has. So I, I don't know I'm not seen flu or kitten. But if it does something like that, I, I'm not a fan of that. I think that the concepts of monad and stuff are very useful and I definitely use them enclosure, but I usually roll it myself. Right. Like I said before, it requires the discipline, like I make, I think this is a monad, this is a state monad. It needs to carry its state. And it also has a separate return value, you know, I, and I, so I return to tuple with the current state, like the new current state and the return value and I destructure it like I do it all by hand. And, you know, I, I should look at this library. Cool. There's a comment followed by a question. So, Dr. Smith says, I think there's pushback in the pleasure community from pursuing algebraic onset enclosure, but having words to call an F sharp, I find them very valuable. You said the pleasure community would embrace that eventually, or is it not simple? Wow, these are really good questions. So I, I, I tend to agree. I think that there's, there's a reluctance in the community for algebraic ideas. It's the same reluctance that you see in other programming communities. For, you know, so I've given talks on algebra at closure conferences. I think that the ideas are important. But in one of the talks, I made the joke that item potency is the only algebraic concept that programmers are willing to, to accept, to say to talk about anything else is sort of a bridge too far. And it's, you know, it's too, too mathy. I don't want to get into math, you know, like this fear of math. So, I don't see why it's not simple. Right. So I don't think it's this, it's a, it's because it's not simple. And I think that if you read some of the doc strings for functions in the more advanced parts of closure, like reducers library or transducers. Tiki, who wrote those does mention associativity. He does mention, monoid, you know, these ideas of algebra. And so I feel like it's there. Right. It's in there. It's just maybe it hasn't been presented in a closure. Anyway, for instance, closure has a pattern for, for defining monoids. Most lists do. And you use it all the time. So if you have the plus function. You can call it with any number of arguments. You can call it with two arguments and that's, you know, just adds them. Call it with one argument. It just returns it. With zero arguments, it returns zero, the identity for plus. And the reason you can have three arguments or four or 100 arguments is because it's associative. Right. Because plus is associative. The parentheses don't matter. Right. You know, if you were to write it out in mathematical notation, associative means the order of operations doesn't matter. So plus is allowed to, you know, because you don't want it. You don't want to have to nest these plus, plus, you know, calls to plus in an expression. You can just put them all as arguments to the single plus. The pattern you see in many lists, and it's a pattern that is now kind of made made super obvious in the transducer's library, where a lot of things need to be that way they need to be, they need to return their identity when you pass in zero arguments. The thing is, if you say monoid, no one knows what you mean. Right. It's not something we, it's not a term we use all the time in the closure community. I mean, it's the same. Yes. So let's see. There's, maybe we'll do one or two more questions. Here's one from Proctor. Eric, any tips for people when it comes to identifying the identity value when doing the reductions on the complex data structures? Yeah. So just for simple data structures, it's usually the, the, if you were going to like do a for loop and you had to initialize your for loop, what would you initialize that variable to. Right. So you're going to initialize your, if you're, if you're like adding stuff to a, to an array, you'd start with an empty array. If you're going to add up some numbers, you would initialize the sum to zero. Right. So those are the identities for those operations. For more complex stuff. I'm going to talk about the Starbucks case because that's kind of a pretty complex data structure. What's the default coffee. It's kind of a business question. Right. Like, if someone just said, give me a coffee. Like, what would you give them? Right. That's the default. Like, what is loaded up on the screen when you first open up the app. Without any additive, you know, obviously it wouldn't have any additives, probably be a small, probably a medium roast. Right. So, you know, just like easy, easy answers. For the complex ones. If that's not like user facing like that, where there's like an easy business answer. I would look at your operations. So define some combination operations that, that, you know, combine two of these data structures. And I would, if it is indeed associative, I would look at how the individual pieces combine. Right. So you could probably figure out, oh, well, this, this is associative because it's built out of these four associative operations. And those associative operations are like operating on different pieces of the data structure. And so what are their identities? Right. Now, if it's not, if it's not an associative thing, if it is like truly a reduce. It's, I don't know, it's whatever you want to start. Whatever, whatever is the real starting value. Awesome. And then let's do last question. So here, ENS. How can I relate transducers to monoids? Are there some articles to study and relate? And I can only think of how you can relate reducers to monoids. So transducers work in sequence, right down like a list or down a, a core async channel, something like that. And so, all right, I need to back up. This is a, is a tough question. So let me define monoid. So monoid has is a, as an operation that has an identity, and it is also associative. Okay. So when, when you're doing a transducer, there's often an identity. It's the starting value. So if you're doing like just a simple map transducer, the starting value is the empty array or the empty list, right? And you're going to concatenate onto the end of it. And if you're in your associativity is the concatenation operation, right? So you're concatenating when you, associativity means that the order of operations doesn't matter. So if you imagine you have three strings to concatenate. You can actually concatenate them in two different orders. You can connect concatenate string A and string B, and then add C to the end, or you can do B and C first and then add A to the beginning, right? You get the same string out at the end. That's what associativity means. And so when you're doing this reduce or transduced, you're actually putting the parentheses on like the first two. And then one more, and then one more, and then one more, and then one more, right? So you're doing the A plus B, and then plus C, and then plus D, and then plus E, right? So you're, you're doing it in a certain order. And it's the order that they're coming in through the transduction, right? But what's nice about associativity is that you don't have to do them in that order. You can, if you have all the values, this is what happens in reducers. If you give it a vector, you can cut the vector in two. You can run the same operation just linearly through one half, and the same operation, the second half, and because it's associative, you can just put them together. You don't have to care. They don't even have to coordinate just both done, put them together, right? And you can do that recursively. You can cut it in two, you can cut it in two, cut it in two. So you're having all your cores are operating on different parts of it. And then as they're done, they're being recatenated together, and you have your answer. So that's how that's what I would say. Awesome. Thanks a lot. So I'm going to put your slides back up there if you want to put your contact in. Cool. Well, I want to thank you for speaking to us tonight. I learned a whole lot, and it definitely seems like our audience did as well. So thank you so much for speaking. Yes, of course. Thank you for having me. Yeah, awesome. And then let's see. So for all of you that joined us, thanks a lot. And we hope to see you again. Likely next month will be online again. So obviously, if there are speakers that you want to hear, and I mean, if you're on Clujurians.net, there's a lot of people to choose from. I think there was something like 17,000 people in there. If you know someone that I should be nudging so that way, we can get a speaker for the coming month, even virtual speakers. Definitely reach out on the meetup or definitely reach out in the Slack channel at Mid Cities Meetup in the Clujurians Slack. So thanks again for coming, and we'll see you next month. All right.