 Yeah, like Brandon mentioned, this is roughly designed to be a follow-up to his talk. I did take some time to talk about things in a slightly different way. Keep in mind, I'm also not an expert, I'm not Ed Komet, I'm not Brian McKenna, I'm not all these people you would think about as a functional programming experts. I mean, I've been working with it for quite some time, but I'm definitely not the master. So, about me, I'm Colt Fredrickson, I work at Oracle, we got bought up by them a few years ago. I work on a big data, there you go, drop that word, team and we do some interesting stuff with Scala. I've been working in Scala since 2011. Originally I started writing it as better Java, you know, because it's, it is, it's way better than Java, even if you just write it like Java. But then once you start getting into these problems like Brandon's talking about, where you want error messages and you want to combine failures and all this stuff, you do run into some interesting things. So, ask questions, at any point you're confused about what I'm doing or why I'm doing it, just stop me. This is not designed to be, I'm gonna go all the way through to the end and then there's like, ask a question about something at the beginning, if on the way it doesn't make sense, please just stop me. So, Scala is that is just functional programming language or functional programming library for Scala. It's basically trying to take principal data structures and that kind of stuff and use them in Scala. Now, what typically happens when you show somebody Scala is that it's roughly this. If you walk up to a standard Scala developer who uses this as a better Java and they just like, what are you even saying to me? Because they run the stuff like this, like modad trans of f of higher kind of this and this and it takes arbitrary types and they send you a chat message that says, I have no idea what this means or how it's useful. And so, you know, that's not really what you want people to be dealing with or this. It's like, okay, it's a function for me to be but look at that type, like look at the symbols, like if somebody doesn't understand lambdas and alphas in the first place, in any sort of category theory or something like that, they'll just be like, I don't want this. So really, it's not that bad. It's certainly is filled with symbols and it certainly is backed by theory, but you can pick little itsy-bitsy pieces off and use it without like biting off a modad trans right off the bat. Like you don't have to deal with that. So before we talk about all those data structures and type classes, the Scholasy package structure is a very interesting beast. So we're just going to kind of go through it and talk about it and hopefully you can all tweet out these slides afterwards and you can come back to it and kind of use it. So all data types are underneath Scholasy base package. So like even the type classes like Functor, Monad, etc. are under there as well as Clisly, non-empty list, etc. So if you want them all, you can import Scholasy underscore and you'll get all the data types from Scholasy. But if you want them, you can import them individually. So syntax, a lot of what Scholasy offers is the stuff that Brenda was talking about with like Star, Greater Than, or Pipe at Pipe, Pinkie Pie, whatever you want to call it. So you can get that syntax by importing the data type dot underscore. So if you want to put either syntax onto your standard data type, so you can put like dot left to lift something into a left side of a disjunction or dot right, you just import Scholasy syntax either underscore. Also note that it's wildly confusing that it's either or not disjunction when everybody calls it disjunction. But that's the way it is. Same thing with equal. If you import equal dot underscore, you get an implicit def that basically converts anything that has a equal type class into something that has syntax for triple equals and equals slash equals, which is a more safe way of dealing with equality. And the same thing with functor adds map and map to your stuff that has a functor type class. Or like I said, you can just get them all. So you will run into the scenarios where you're starting to develop in a file and you don't know what you need from Scholasy. So you start with the import scholasy dot underscore scholasy dot underscore and just like work in there. But I try to avoid personally committing that unless I'm, if I really am leveraging a lot of things, I'll switch to like, well, I'm getting it all. But otherwise, I like to put comments about why certain imports are there for just to help out my coworkers really. So you can also get syntax for standard library stuff. So a lot of what skull is that also does is add syntax to standard library classes, like interspersed on list or, I don't know, there's a bunch of other examples. So you can also get standard library syntax stuff from the syntax to std dot whatever package. And then you get type class instances from Scholasy, std, and then the type name dot underscore. So all this is really a little bit confusing. And so there's a friendly guy C dubs, Cody. He has a flow chart for this. That's how complicated it is. So this flow chart is at this URL, which I'll tweet out. But he was ultimately responsible for that. And so you just start at the top and it'll be like, Well, what am I, what am I looking for? What kind of error messages am I getting that kind of thing? And I'll walk you through what to import. It's kind of sad that we need that. But same time, things are split up. Okay, so let's dig in. We're gonna talk about a couple types. We're gonna talk a little bit about non empty list. We're gonna get into a little more. And then we're gonna talk about type classes. So I said I was going to talk about non empty list. I kind of am. There's a there's a type called one and, and it's parameterized on a type F. And that this allows you to say, I have at least one value of, of type A, and then I have a tail of values that are in some type F. So when you think about naturally a list, you have a head and a tail, obviously, this fits really well, or the, you know, the head is that type A, and the tail is the list. So you can define non empty less in terms of one and scholars that didn't. I think it's probably because they just wanted to put a bunch more functionality on there and not expose out that type. It's also, I did note that one and is invariant. And a non empty list is not invariant. So that might also be the reason that it's okay. It doesn't actually work correctly to the extent that now can be defined in terms of that. So that's part of why it's okay. Sure. Oh, okay. So yeah, in 72, there's variants on. Is there invariant? Yeah, it may not have to list invariant. You're a bad person. Okay. So non empty list. This is the point at which I if you have a list that you know isn't empty, and you return out the list type anyways, you're just being a bad person to your consumers. You're basically saying to your consumers in a comment or whatever, Hey, I guarantee this list won't be empty. It's safe to call head on it. And then they end up in if they're filing any kind of Scott style guideline, they're going to have like a head with a comment that says, I'm sorry, future me. Really, this is safe. It's like, we have types for a reason. Let's use them. Okay, soapbox. So box over. So non empty list. There's two constructors we're going to talk about. So the there's basically just if you pass in the head and some list as the tail, and then there's a var version of that that allows you to pass in any number of arguments and it'll make it into a list. But it's exactly what you'd expect other operators like, there's a maximum by there's a minimum by there's all kinds of list functionality on there. As well as you can see here, I mean, that the head is a value, it's not a depth that will throw it exception. In some cases, it's not partial on any kind of way, it is a value, you know it, use it. And so if you're desperate, and something you're going to call into needs a list, it's a constant time operation, just call dot list on your non empty list, and you'll get back the list. So you could pass it off. And then sure when you get it back, like, okay, maybe you have to do that ugly thing where you pattern match and like, well, this, this shouldn't ever happen. But I had to do this because of whatever reason. But if we all agree that non empty lists are a thing, then we could just stop, you know, having functions that only operate on list. So non empty list. I just wanted to give like some examples of where this is a really good idea. So in Addo, which is a thing, Rob wrote, parser library, there's the ability to parse match many of a particular parser. So I match zero to n matches of that parser and still succeed if there's zero. If you're if you want to have at least one, the return type should be non empty list, because we know that there's at least one. Like, so there's none of this magic where we have to figure out when I call many one is was there one for sure, I know there was because that's what the documentation said. But now the type says it to So let's see, lost here. Okay, so here's another interesting thing. So say that you have a thing called validate users, like Brandon was talking about validating users. So we here we have something that takes a list of users and returns you a validation of non empty list of errors, like we're talking about, or a list of users. Well, is an empty list of users a reasonable thing to validate? Are we saying for our particular use case that empty list is valid? If we are, then that's the data type is entirely precise. But if we're not, and we actually said, you have to have at least one user, the second type is right. So it's just tried try to be as precise as possible with your type to help out your users. So it's all about precision. If you're, if you're talking about your types, we have types, let's use them be precise. So let's talk about validation. We just got done talking about it a bunch. But it, it looks just like a disjunction. Right there, there, there's left, that's failure, there's right success. It's, it's not entirely obvious. At first glance, why it is what it is. So you get some operations on validation. We just talked about validation NEL. That's just conversion. Disjunction, they're completely isomorphic to each other. It's always like safe to go from a validation to a disjunction and back to a validation. So if you need to, for instance, use it as a monad, a flat map over it, you can just convert it to a disjunction, use it in that fashion, and then convert it back at the end. Do note that you'll lose the error accumulation on it when you do that, because you've converted it to a disjunction, but you can do that if you need to. So this is another place where sure, it would be inconvenient if you couldn't do these isomorphisms easily. But if you can do these isomorphisms, there's just no reason to not be precise about what you were, what you're doing. So if you're doing validation, use a validation. Go just make a point about the whole like, applicative versus flat mapping kind of things with errors. It really comes down to what is your error handling want to be? Is it halt on first error or is it accumulate? Yep. Just something to keep in mind. Yep. And you might switch between those in your domain. Like at Brendan's lower level, you might want to accumulate all these low level errors. But at the top level, you want to fail as fast as possible. So you can switch between these two, you don't have to choose. They're isomorphic to each other. So it's not a monad. So the first time we try to use it in a fork comprehension, you get the error that you can't. Just don't be too sad. So here's just a couple examples. And I use the Pinkie Pie syntax here. But we don't even need to really go into these because we talked about it a bunch in the last section. But basically, it's just accumulating errors on the left. And it's calling the function with the success values if it was a success. So I don't really, yeah, that's all I have to say about the actual data types. Does anybody have any question about the data types before we move on to type classes? Perfect. All right. So before we go any further, I just want to take a brief aside. Everybody here probably knows type class syntax. But it can get a little weird if you haven't dealt with this before. So functor in this particular case is a type class over some higher kind of type F. So that's just saying a type that needs another type before it's actually a full type. And so what we're saying here is list instance is defined over just list. It's not defined over a list of a or a list of a specific type. It's defined for all lists regardless of what's in it. And then the a's come in in actual functions. So map is defined for any list of a given a function of from a to b. So Daniel has a talk from quite some time ago, high wizardry in the land of Scala about higher kind of types. So if you don't know about higher kind of types, and you want to learn about them, I do recommend that talk. It was like basically three years ago or something crazy now. But I think he does a good job talking about what higher kind of types are and and why they're useful. And just the terminology that surrounds it. So yeah, why should I think most of the talk is just like star to star to star. So there's there's a lot of stars in there. So let's talk about the semi group type class. This is a type class that's just saying you can add things together. So the reason it's not called like additive is because I mean, addition is also commutative. And there's like, there's a bunch of other stuff. The only laws that deal with you deal with when you're talking about a semi group is associativity. So you got to be able to add together and B to C. And then, you know, and B or a to B and C, like, that's, that's the only law, the only way it has to work. And there is such a thing as a commutative semi group. If that's the kind of restriction you need, it doesn't exist today. And Scala said, I've talked to Lars a little bit about it, but I haven't talked to him since like the whole switcheroo. So semi group. This is a there's some really interesting things you get from semi group. And this is just one of them. I defined a little thing here that is wildly useful to me a lot of times, where if I want to update a value inside of a map, and if there is a value in there, I want to append my new value to it. If there's not, I just want to put it in there. This is something we want to do all the time. Like, here, I've probably written this function, like a hundred times before I discovered this, over different types before I understood how I could do it better. So all they did was say B has to be a semi group, and it'll, you work for any map A to B. And that little bar plus bar, I'm going to leave it to Brendan to name it. But it's basically the syntax for append. So I could have said append there. Now it's obvious I had to have the syntax and scope and all that stuff. I didn't show the imports here. But so if I append a map or the keys lineup, it just adds together those two lists in the value. So the, the semi group for list is just appending. In the second one, like you can see, since the keys are different, it obviously just put the first value in there. So that's all I have to talk about with semi group. It's fairly simple. Monoid is just the semi group, but there's a zero that you can put in anywhere. Think of zeros like the zero for addition or the one for product on numbers. Identity. Yeah, they call it zero. Exactly. So that's a great problem where zero is the identity. And they probably should have called it that, but they did. So there's the, there's the laws. I don't think we need to go into them. So it gives you a few simple things. Multiply just appends a value together end times. You'll run into a lot of cases where you're going to want to check to see if something is the identity or not. And then you've got the empty, if it is the identity, do something special. But the, the power from Monoids does not come from using them by themselves. It's what you get from them when you put that together and we'll talk about that a little bit. So here's just some instances of Monoids. You'll find them everywhere. Once you start thinking about things like this, being able to add data structures together is almost all of what we normally do as software engineers. Like we're, we're fiddling bits. That's basically our job. So here's a, here's an example of something that I wish that I had a lot of times is better some. It's basically for anything that could be added together that has an identity, I want to sum it. If you try to call some on something in the untroversable once, and it's not numeric, like you'll get a compiler. And that's not what I want. I want to be able to add together strings and I want to be able to add together options of values. And I want to be able to add together all these different types of things. So here's the really fascinating one that, that I find wildly useful is being able to add together maps. So you can add together maps where it's for wherever the key is equal, it's going to add together the value for you. We just talked about that a little bit in the last one where you want to update a single element. But what if you just want to merge two maps? That's something like I end up wanting to do quite, quite a bit when I get back something that looks like JSON, I'm storing it in a map in memory. I just want to add together those values and then I'll turn it back into JSON or whatever. So map is a monoid if the values can be appended. So that's just saying, if you have a semi group for your value, you can add together maps. And that's an example here where A, in the first example, two and three got added together. In the second example, it didn't. So I find like the monites are just so useful. You'll run into this all the time once you start thinking about it. Anytime you can add two things together and think, well, if I just made this a monoid, like what am I, what would I get out of ScalaZed for free? Being able to, being able to leverage that. So you'll see it all over the place now. The next one I want to talk about, we're going to take a pretty significant jump in terms of mental energy expended from monoid. But foldable is, is a wildly useful type class. So you have to implement either a fold map or fold right. I'm not going to talk about fold right right now. I'd like to think about it in terms of fold map, because then it's basically like map reduce. So fold map, you have some container thingy F, and you have some function that goes from A to B, and you have the ability to add together B's. That's all this is saying. If you do that, what are we talking about here? I mean, we are talking about map reduce. You map, then you collapse it all into one value. And so it turns out this, this comes up all the time. There's no laws per se, except for the consistency laws. I, I somehow, I went back to the original paper and it seems like there should be one more law, but I haven't spent any time working on it. So this gives you the ability to like do things like length on some data structure, convert it to lists and sequences and sets, minimums and maximums. I'm going to mention fold map M here, because it's so cool. Once you see, see that you need to use for it. But that's just going to some value G, which is a monad. Just, just if you start, if you start ending up in a place where the value you're using inside of your fold maps are monads, maybe this is what you want. Just start poking at it and come bother us on IRC when you run into that problem. So give a couple of examples. I'm going to give examples mainly in terms of collection things, because that's what most people think of and what most people can derive good uses for. But any structure that can be collapsed into a single value in a consistent way is foldable. So you could run into some places where this is worthwhile in something you have yourself that's holding onto values. So fold map of identity over integers is the exact same as if I just folded left, seeded the fold left with the identity and then accumulated the values from left to right. It's exactly the same. So now we've got if we've got a list of maps like we talked about before, maps are a monoid if the value is a semi group. So you can fold over this list of maps if you want to accumulate the values at that where the keys are the same. Now you might run into an issue where you're like, well, that's not what I wanted at all. What I really wanted was I want to sum up all the values inside of the maps. So you you can compose foldable structures into a foldable structure that's bigger. So if you have a list of maps, you can collapse the maps together. But if you want, you can create a foldable structure that operates over the list of map and just fold over the values. So this is really neat when you come into this place where you want to ignore the keys in the map and just collapse all the values together. So here I went. I summed a foldable of list. I composed that with a map foldable for map of string to some value. And here I'm using not the super ugly syntax of symbols for that type. I'm using kind projector, which if you deal with higher kind of types at all, you should probably take a look at. But then I fold map over that that list of maps up top. And just in for a change of pace instead of doing just the identity function, I added a hundred to each value. So what this does that takes 101 plus 102 plus 103 and returns you the value. So sometimes it's hard to see that this is what you really want because you've written this deeply nested code that kind of looks like a rat's nest. And all you wanted to do is just pull out the values and add them together. So sometimes when you have something super nested and ugly, stop, think, could this be solved with something slightly better? Sure. So this is, it's a whole. So that's to say, foldable structures, if you remember are defined over f of underscore. So you can't fully specify a type. You have to have a hole in your data type where you want to declare your foldable structure over. This is using, I could have used, you remember on the first slide where Pinkie is vomiting herself up, I could use some super ugly syntax like that. This is using a compiler plugin called kind projector that allows you to forego the ugly syntax and just use a question mark. Stu might talk about that kind of stuff when he talks about cats, because they use kind of projector all over the place. You kind of think of the question mark there is filling in the type of the list where it has foldable list. Yeah, it's it could be a type alias too. Yeah, you did. I could have done that. And I maybe show. You could write big lambda. Yeah, I think I'll avoid the lambda if I can. Not hardcore enough. Yeah, more specifically, I don't like scaring people away. Um, so we've talked about foldable, which takes a structure of some big structure and collapses it down into one value. Now let's talk about traverse. And if you look at the Haskell stuff as this traversable, but that's kind of taken by some of the scholar standard stuff. So they chose to just go with traverse. But basically this goes from some structure. And for every function in there, you're going to some other value, some other applicative value like validation is a good example, or disjunction or option. And see the return type at the end there G of F of B. So we went for each element in our F, we're going from an A to a G of B. And we're basically constructing one big F of G of B's. And we're then just going to flip that structure inside out. So the first time I saw this, I couldn't believe that it was a thing and I couldn't make any sense of it. So just think about it as the thing you probably always want. It is true. It's almost always the right answer. If you have a list of things you're going to validate and you go over it and you create a list of validations, almost what you want is a validation of list, because you want all your successes together or you want that failure. So let's just dig into some examples. So first, I'm going to talk about the super ugly thing that exists. So Scala C isn't the best at type inferring, higher kind of types. So actually let's just say that it can't. Let's just say it can't. So the clever people in Scala Z and they invented these weird unapply super ugly things. I only put it up here almost for like laughability sake. Don't pay attention to the these versions in terms of the type signatures, but always use them. Almost always what you want is traverse you instead of traverse impulse because the type inference on in Scala C is bad. It's just the way it is. Just use them, but be afraid. Be very afraid. So you're saying that that's what we should use as an end user, not when we implement our own traverse. Correct. Yep. You implement traverse impulse. So you get to implement it in terms of that nice type signature. Now, the unapply things that we that are in this slide only exist for the most common shapes. Oh, God. But I haven't run into an instance, especially in the in the gateway drug like casual user where you're not hardcore and defining your own traversable types. You will you will have much deeper knowledge of this stuff before you have to create your own just using what's there. So just don't pay attention to the type signature. Use it and come bother people if you if you have problems. This is basically like what's going on there is basically the very tip of the shapeless. Yeah, there's if you start going down that path, you will land in shapeless. There will be a lot of yelling, mostly fear. So let's talk about this. I said it's what you almost always want and it is. So if I if I map over some function, just pretend that I plus 100 could fail in some case, I'll talk about on the next line. But I if I go across that and I map it, I end up with a list of option of int. Well, that's probably not what you want. I mean, if you it is what you want, sweet, you're you're covered already. But if you call this sequence you on the end, it'll flip that structure inside out. So you can see in the second line, instead of getting back a list that has some failures and some successes, you get back just the failure. And then you can fold on it, pattern match on it, do whatever you want with that option on the outside. Um, so traverse you is just map plus sequence you. So if you find yourself mapping and then calling sequence you, you can just replace the map with a traverse you and delete the sequence you. It's actually a lot more common than sequence you. Yeah, you're almost always mapping, right? You're almost always mapping anyways. But I find I found myself when I first started using this stuff, I would just write the map and be like, oh, I need to flip this thing inside out, tack the sequence you on to the end and then you're like, oh, I see this common pattern. I can do it in one call instead of two. So this is just the same code. I just replaced the map with a traverse you and got rid of the sequence you. Like I mentioned, OK, so validation is where this typically comes up. You're validating a list of things and you want to get back all the failures or you want to get back the success. So I define just a type alias validation of non empty list of string. And then I valid validate user returns on my validation of user. So I take some string and presumably creates some user out of it. So in this case, I end up with I've got list colt fred bob bunch of symbols and let's say symbols are not valid. So I get back a failure that has a non empty list with both of the error messages in it. So I accumulated all the errors or I would have gotten back the user which I is the success. So you're going to get back a failure with all your errors which is a non empty list because you know that there's an error in there. If you're getting back the left side or the failure side or you would get back the user. So if you look at the scenario where there is just valid users, you get back a success with lists of users. So also know like we're talking about your validation code is still written in terms of a single user so you can unit test it really nicely but then you can comprehend across it or traverse across it using this nice traverse you thing to accumulate lots of successes or lots of failures. So that is it. Thank you.