scale.bythebay.io: Ryan Delucchi, Functional Patterns and Gems in Scala
Recording: scale.bythebay.io: Ryan Delucchi, Functional Patterns and Gems in Scala
you thank you for coming this is uh we're gonna be talking today about well it's an FP talk where we'll be discussing different patterns and what I like to refer to as instruments of functional programming and some gems that we'll take a look at along the way so what I'm talking about patterns I I'm referring to the the fact that that our brains are are evolved for pattern recognition that's that's the driving force of how we reason and there's a great paper on this my mark Madson from John Hopkins John Hopkins University so I talked a bit more of this at length last year where we talked about object-oriented doesn't quite live up to its promises and how that applies to patterns pattern recognition well loop was designed to model physical objects with the with the the idea that you can represent software systems using physical objects as well but transitivity doesn't apply here so you you lose you lose a lot of the benefit of using open in your software designs so we're going to look at first a world without referential transparency which once again it's become pretty well known phrase at this point but just to recap referential transparency is about divide what your your software being defined as a collection of functions that their output is is governed entirely by their input independent over space and time so take a look at this now probably we stare at this for about 30 seconds you might sort of see what's going on but you're not seeing it right away you have to sort of parse through it and and you know spin up a Turing machine in your head to grok what's going on here how about this you probably saw it in about five seconds maybe even less because you recognize a parent okay this is sequel and and you're you see what's going on here pretty much right away well we know both languages we know Scala and sequel but sequel is a declarative language by nature assuming you're not doing you know funky things with cursors and such but for the most part you're you're it's it's a it's a declarative language so that really aids us pattern recognition now syntax is part of it actually so if we were to say okay well we'll turn sequel into a into a list like language I I would I would argue you're still you're still recognizing the pattern here what's going on faster than the declare the the imperative form but you're but there's a little what I like to call syntactic camouflage here because you have lots of parentheses and you kind of lose the benefits of the insects in fix notation which you have in languages like Scala now let's consider this another perfect example you take a look right here and you say that we're manipulating a mutable stack here pushing nodes here probably take a little bit to really realize what exactly that is well I'm going to show you this real quick before you get it that you probably see it right away what this is is a depth-first traversal so the same thing and and FP a lot of FP is about using recursion and this aids with pattern recognition now going from other or going from a more imperative languages like Java it's it's tempting to look at Scala and be be really focused on the fact that okay we're in we're into the whole brevity thing I want to make code more succinctly the question is how quickly we see these patterns and when I mean patterns I'm I need to be precise Here I am NOT referring to code formatting in style and i includes names however names can mislead you so you have names where there they are - either they're too precise or imprecise meaning the per they might refer to a special case of what your code can actually do versus names that well are essentially comments that haven't been updated and trying to structure your code using comments since what I refer to syntactic code reviews which is for example all the different string libraries where you're not really reusing any deep semantics but just just syntax for convenience so today we're going to be looking at a cross sectional view of some of these category Theory concepts once again I like to call them instruments of F P P RFP and we won't be going too much into the rigor although I will be going showing showing applicable laws I see going into more the more rigors of category definitions in the future so that's why I put the little at least for now on there so okay so we know what pattern what I mean by patterns what what do we mean by gems and well obviously is an example right here like say you have an imperial description of and a conditional well here's a nice gem right here you can actually fold on a boolean for true or false so not too many people know about this it's really quite nice it just as you can fold on other data types here's another one and it's essentially it's a fold cata morphism which which is actually a fold here on an option so if there is if there's a value there your turrets at length if there if it's not there you'll say zero so once again you see these you see these expressions here in you can instance see it instantly see what you're doing and once again this is referred to as a cattle morphism and you you have flexibility on actually performing these on the variety of algebraic data types and I just to keep the the slides from the font size from going down to 12-point font I'm trying to will leave imports to the end but I promise I'll be showing some import statements so that so that you know if you want to use some of this you can so what what I'm referring to here this is sort of a consequence of taking a cross sectional view is that I'm referring to this notion of sequential chain computation that is a declarative okay and I'll you'll see what I mean by that and by explaining what that is I this right here is not sequentially chained you get performing the power of two of of these values independently of course reduction is going to is going to walk through the walk through the sequence there but but the point is this is not this is not what I mean by sequentially chained declare of computation however this is but except it's imperative and we're saying we're performing a sequence of steps and then perform an effect on those steps now we referential transparency comes back again we we have to assume that these are referential traffic referentially transparent or our reasoning goes out the window so just keep that in mind now it's it's easy to take for granted what we're doing here when we only list steps here in effect on them so I'm going to be Tribe use precise as I can about this and say that okay these are statements and there is there's a governance of of these statements which is by a procedure block so there's no laws or constraints and no real conditions dictating the the constraints on those on those on the on the procedure block so we can however if we're if we are doing if we're if we're leveraging the function signatures and okay we have constraints here so we can compose them a show Esso and the compose and and then just shows two forms of this so here here we do have we do have actually some governance here buts on actual the the signatures on the functions and this is this is starting to touch on on a really important aspect of FP FP which is that all of the structure and intent of what what you're building ideally this could be represented by by your function signatures and this is really interesting because well notice there's no real names here and the point is that we don't really need names they just sort of act as placeholders so that you know which which values we're talking about but the point is the types and here I mean you probably look at this you can guess what this does you have a list return int that's probably we're gonna return the link to the list right here you have you have a list and you know integer that's probably the guess single value from the list right here probably guess what this does right anybody want to sorry I'm sorry uh that's yeah yeah this will this is a find and then the second one's a filter yeah so you see the different services of a fine and this is a filter of course that might be an option int but uh anyway fine first so and then right here you would have a bright guess what this last one is right partition exactly now of course some of these you could probably think of maybe a few other cases that that these could do like right up here maybe this would be returning a value index from the end to some arbitrary point so a fun exercise would be to take these and split these further until you reach the point where you can't think of any you can't think of multiple meanings for the different functions okay so we're gonna define a full-fledged context as a monad and this will be we're gonna call it the planet mode ad all right so something you probably haven't had to do yet so which is why I chose ptosis concepts I don't want to have have some sort of incidental associations with the with what I'm defining versus the concepts I'm explaining so we're going to find a planet monad and we're gonna say a planet monad represents the boundaries of all enclosed mass of type a and what I mean by that is well a represents really the stuff that the planet contains it's it's really the planet but planet of a is well this earth is this Mars is this Jupiter and it's going to be lawful and I want to step through the laws real quick here where let's say we have a function that takes in a mass and gives us a planet a well the left identity law says that if you take that if you take a mass and lift it into some sort of arbitrary default planet and flatmap it way F right here then you should get the same planet that you would that that would that would materialize when you pass mass to F now we look at this in for comprehension for them it's actually easier to graph the law and you're going to see that a lot in this and that's actually an example of a pattern right there because with a for comprehension once again for for folks that may not realize this you're you're really doing a sequences of flat map followed by a map okay so people refer to it as as as sugaring syntactical sugar but this actually once again syntax does play a role in in in pattern recognition and this actually helps with that yes so at that point that is what that that also referred to as pure or unit that what that does that takes that takes a value and lifts it into the context so it it will take a mass which would be a type a and then when you point you say point it will actually you know it will generate a planet of a and and yeah so so we're doing a point we're doing a flat map there now the right of Dani law says that let's take a particular planet Saturn we flat map it with here doing a point on on the mass then we're gonna get Saturn back and you can kind of see a pattern there in both cases you have an actual you have an actual planet you see it on both left for and right ideas you have a specific plant that was defined and you end up with you end up with an equality there on that as a as a result of the whole thing and here is the here's it's shown as as a for comprehension now finally we do the associativity law which basically states out Udyr take two flat maps on across two functions and I will be equivalent to doing a flat map or then doing the flat map in word of the of the first flat America call now this looks really interesting when you look at the four comprehension it kind of looks like if you're looking at abstract syntax tree and you can take an operations it sort of shifted upward or downward in the tree that's that's what this looks like so so yeah it shows that you you can actually that these these are equivalent to each other that's the associativity law for monads now we're going to say that planet a is also a functor so there laws there as well there's identity law where I Deniz usually defined by I'm defining here just you know for clarity you take neptune and map it across the identity function which is supposed to entirely preserve this the same values and it will equal the same and then you have the distributive law where you could do two maps or you could do a single map and then actually just call the second function in word there directly so these laws have to apply for your functor to be well-formed and once you follow these these laws then you gain all the benefit of the pattern recognition that they're in you know continue talking about all right it's time for doomsday you probably saw this coming we have we're gonna have Earth's Mars and Venus crash into each other and we're gonna do that using this function doomsday which takes in a sequence of masses and will give you a resulting mega planet planet Union as a result so this is were once again revisiting what I which is a declarative sequential chain computation and we're doing this within the context of a planet mass so going back to early example we have step two step step one step two and step three now we have the same thing but is now governed by the structure of a monad within the context of a monad so this gives you more guarantees it gives you more gives you more precision about what what you are able to do and what we're doing here is we're saying okay we're going to take the masses of Earth Mars and Venus they're about to crash into each other but we need to prepare the humans and Martians and the venetians for collision so we have functions for doing that and we also have the option of taking those functions and lifting them to the monad level and the pattern there is that now these these functions themselves actually return type planet a as opposed to just just just altered mass based off of their preparation and you structure a little bit differently you know comparing the two it's you know it's arguably I would say it's arguably cleaner this way because now you're just calling the function straight away and it's actually going to comprehension but yeah so that's those are two ways you could actually structure it assuming that your functions are returning the actual monad type now what do we what are we what are we gaining from implying a monad structure to this this sequential computation well we're we're it gives us the ability to accumulate a full context and as your contact is building up you are you're you're progressively building up what is going to be your final result because if these were separate functions let's say we go back to our example before where we're taking separate functions and just calling them chained in a row well if we want to call another function at the end it's going to have to take the values of all those previous functions so you have to do all this ad hoc sort of thing we're taking values putting them in you know putting a sign amt2 other values and it you start have to you have to basically you're thinking more to solve your problem then you really have to where as here your your operations are governed by some principles and you can actually build things quicker actually and that's what this is about so so right yeah that's what so that's so without a monad it becomes a lot there's a lot more ad hoc sort of work that you have to do now taking this further we can take planets and actually in the code the the for conversion looks the same we can lift all those operations into an algebra and by doing that now there could be a transformation from planet up to plant it so that and that's achieved using a natural transformation and this is actually the basis of how we get of how free monads work using cone ADA and I don't get too much in the coil NATO or defining free monads and this talk to lots of talks about that I didn't want to duplicate that right there so yeah I definitely recommend looking looking into that and Kelleen ADA as well which is really about taking a data type in and treating it like a functor so anyway so we're going to postpone doomsday and the way we're going to postpone doomsday is we're going to say that okay all these operations we're gonna turn them all into dis junctions some types and meaning a computer or failed or there's a mass returned so the idea being that if preparation it's like oh we don't have enough we don't have enough spaceships to take everybody off the planet okay we're gonna we're gonna return preparation failed with the presumption that doomsday will be suspended which is great because he could just lie and say that you weren't able to prepare and doomsday will never happen so so we're time for another gym for disjunctions where you have like either an air condition or value as a result you can perform a merge if both sides are of the same type in this half this is actually a really useful little gem where you're doing a lot of processing with with dis junctions and you end up the case where well really it's a success on either side or oh it's an error on either side you can do emerge on that so very handy so we're altering our original our original sequential chained execution here but now we're using dis junctions and you see it's not too much different however well we have to lift these into actual disjunctions right here these are success masses right here and then right here we do we actually do was known as its reverse which is the same thing as a map in the sequence I find in practice I use Traverse quite a bit more but um and India traverses are very very useful and they're they're important because this final result needs to be a disjunction of either you know see the error condition which we're declaring as an integer here or the the planet planets string actually I suppose we planet mass this is based on some other sample of code so that should be planet mass right there so say you have errors in int and you have a planet planet mass so Traverse what it does it has the effect of inverting inverting your types so as we know that the prepare operations are all going to be returning disjunctions and we need to judge disjunction returning as a result we need to have the disjunction be the outer type and there's different kinds of traversals there's Traverse you there's Traverse underscore this Traverse M and therefore different types that you need to actually do a Traverse on here we're using u because they're disjunctions and U stands for unapplied by the way so let's give a very simple definition for planet a and say that this is just a case class well in order to actually use Traverse on these and since we're defining our own type here to traverse on we need to define a an implicit Traverse applicative and what that what that that has two methods that we need to find app and Traverse simple where what app does is it has this interesting where you take in the planet and also planet of the function going from A to B which that that trips up a lot of people initially my first time I saw it I looked at it sideways a little bit but all that says is that says like you have a planet of some type and that type is a function she was placing a function there in the parameter and that's what we're doing what we're using that here where we're saying we got the planet we pulled up we pull the mass out of that and pass it to the function is to find an F right there and then we form our plan so the app function definition here is quite simple traverse simple well we want we have a planet a and we're going from A to F of B where F is some applicative well we we meet we want to return an F of planet B and that's that's once again that's free or in via this inversion that has to happen so you have to know how to do that and this defines it right here we're saying and doing a map operation over F at F a dot a and then passing it to plant dot apply which is a that just reminder that's a apply method on for case classes for creating a planet and then you have to find point which is pretty straightforward I mean if that's the same as actually constructing one all right really have one last gem here and this is the Scalzi buying syntax and this this is really quite a nifty here where it's really sort of and bind is actually a it's it's referred to as it's the same thing as a flat map and the bind syntax allows you different high-level operations using flat Maps right here so you say you have a list which a 1 2 3 in list four or five year four five four five four five so the idea is the list wants you three to find your structure of you're saying how many elements you're gonna have and this defines the elements so you're actually you have a four or five in place I mean it's flat map so it's in place of one two and three and you can have operations from some algebra where you're saying or do this and then this and then and then finally we have you know say your you have to talk about the Paciello 306 and say you know John drives one of these and you're gonna take a totally random where you have you have a value here and then you actually you're effectively piping this to this function here so pretty pretty nifty so Traverse has some laws here and I'm going to go over these so we have identity Traverse which is saying that if we're if we're traversing we're doing this sort of flip of the structure again we if if if that type is an identity in there well then that's going to be simply equal to if you're just to do a map okay so sort of it's kind of a degenerate case of a traverse where you know your outer type is an identity so that has to hold true if it doesn't then something was wrong with the way you define your traversal then there's this notion of a sequential fusion which is where you have these two tight you have the two types M&N you want you want to be sure that if you're doing actual Traverse and you're doing a what you're doing a map on Traverse and Traverse inside that's equivalent to if you have traversal on the outside and a map inside and then they doing it compose so there's a lot of syntax here to trip up on but once you're as sure as you see the patterns of this more often you can catch the essence rather quickly and so it's quite astounding over time that becomes that comes natural so I invite folks to take a look at these and get familiar with them and see it see the patterns they emerge from these and there's also a purity one as well where you can say that you have a traversal and a point being equivalent to to the point operation you know given given these definitions up here for applicative G and then equal G and F and then we have a narrow one called naturality which is a given a natural transformation you have defined as NAT you can actually there's an equality between you beyond natural transformation on the sequence which is a sequence and a map and natural transformation inside and the last one is parallel fusion which these are really clear out clever names by the way so you have the two different Traverse traverses area to traverse and Traverse here and versus a traverse and then have indeed actual product inside right there like that and then see if they're equal like this okay so I promised I would explain a little about a bit about imports and here's some of the imports that we're using actually here and there's there's actually there are patterns I IREC I recommend installing a ammonia night or if you if you'd like to use IDE you could do that you could go go there as well and just kind of look through the look three different possibilities as you're trying to get your types for doing various things but the patterns generally are that you have syntax of various types and st for STD for standard and of different types you have a few outliers here we have like STD option and options syntax as well as opposed to syntax option that trips me up all the time like I've gotten used to that one but there's there's it can trip you up yeah you know for a while so those are sort of some guidelines on on imports and and yeah I would say I mean during the unconference I gave a talk on a library I wrote there's using cats so interesting work there interesting working scholars it said my I invite people look take a look there's live interesting things happening so and then finally I recommend folks to take a look at the Nelson project which actually is another talk that's occurring at the same time as right now so that's a I I point this out here not not only because I've actually been working on it this year on the infrastructure team Verizon labs but also because there's a lot of Alaia I talked about here you see a lot of these patterns a lot of heavy use of free monads and and even combining different algebras you know using Co products and inject and there's a lot of really neat useful stuff to look out there so highly recommend that and so that's that's it for today thank you ELISA there's any questions oh okay [Applause]