Devreal

Scale By The Bay 2019: Justin Heyes-Jones, A Gentle Introduction to Comonads

Scale By The Bay 2019: Justin Heyes-Jones, A Gentle Introduction to Comonads

Recording: Scale By The Bay 2019: Justin Heyes-Jones, A Gentle Introduction to Comonads

[Music] yeah my name is Justin I'm a pure functional programming fanatic I work at yacht works if you don't know yacht works we provide training consulting in Scala domain driven design reactive architecture so you should check out our booth because we have a really funny t-shirt as well so yesterday we saw a couple of good talks about using pure functional programming in to solve real problems like Netflix and Comcast and those guys were using cats HTTP for s FS - these are libraries that are built on principles of pure functional programming and also they use parts of category theory so that's great for me because my talk is my talks aimed at people you're kind of beginning interesting getting interested in pure functional programming and then we'll work up to commands which is kind of a more unusual topic so what is pure functional programming it's programming with functions that have various properties so we begin with the function maps to type a too-tight be one of the properties is the function is that its total so this means that for all say if a was an integer for every value of a you're gonna get a value back from B you're not gonna get no you're not gonna get an empty or some kind of error you always get an answer the other property is deterministic this means every number we put in there we're gonna get the same answer back your functions have no side effects so we're not going to be writing to a database we're not gonna be mutating any data or do anything useful basically so advantages appeal functions if we program this way we get programs that are inherently easy to test we get equational reasoning which means we can we can use algebra to manipulate our programs and see what they see how they work if they're doing what we want them to do and you can also compose them and also type functional programming usually this advantage that you can if if two things line up the types match you can you can usually compose them and do something so pure functions need help to do real world to solve real world problems so one thing is side effects so a lot of useful programs are going to write to the database they're going to make Network calls and so on so we use the IO monad and what that is is kind of wrap side effects oh so they can be run later we can still use our pure functional code with the side effects another thing is partiality which is the others that are being a total function so a partial function doesn't have an answer for everything so an example might be if you look up some money in database and and they're not there you'll get nine instead of the the person you want it another thing is exceptions so mannered error helps with that non determinism which means just handling lists and mutable state we have the state monad that can help with that one so all of these things are included in the caps functional programming library and cats is really accessible as a great user community so you can always get help and it provides all of the things that make your functional programming usable in real code another thing is a lot of these concepts come from category theory which is a branch of mathematics that describes mapping objects and this is this really great book you can read for free online and also video series that introduces category theory and you don't really need it to to use this stuff but it's kind of fun and interesting and it's quite accessible so cats comes with this large menagerie of type classes and there are basically things to help you take your pure code and use it for useful programs so last year I watched a talk by Rob Norris and he said fine phone to a fine man and see what's nearby so he was talking about this so this talk is pretty much I did exactly what he said so here's mine add in there's front door and you can see that my net is related to fund orient it goes up like this subtyping relationship and just adjacent to my net is is comer net which is also related to functor so you can see how these these categories are kind of related so type classes are implemented like this just they're kind of like interfaces a type class provides a function so if you want to be a thing that implements the show type class then you have to implement this show function which takes some type a and turns it into a string so here's an example of that we just have our own data type the new person and by creating a instance of an implementation for the type class we're basically telling it how to do the show and then it's in this example you can see that when we print it we get this more interesting output so phoned or a functor is actually from category theory and what funny toys is doing is for all of these things to understand what they do we just need to look at signature so first all you can see that the front door is implemented for some type F and then we have this underscore which means that it's going to be further specialized by another parameter so F might be say a list or a future and then when we usually when we implement the map when we call the map these are the types come into play the a and the B so if you remember from the start the talk I had my a a to be function and that's one of the parameters to functor so what functor takes as parameter is is that and this impure value so we have this f of a which means it's a pure value but it's it's been somehow put into the impure world so it might be an asynchronous operation or a list or one of the other things we talked about before so then we were going to apply this function so you can see there were a phone to it does is it can take the pure value out of the effect and then run your pure code on it and that pure code is code that you can test and reason about and all those good things and then it's going to wrap it back up in a new F with the result I wrapped up so here's an example of that and if a lot of your scallop rogram is you're probably familiar with mapping just mapping a list but this is a high-level view of it you're not just mapping a list you're you're transforming a list using a pure function so another common type class is monad which is a subject of our funny t-shirt so man it has two functions did pure in the flat map what pure does is let us take a pure value of type a and put it into our effect type so you can see this simple example which is putting it in a list and then my night also has flatmap which takes functions that have this signature so you have a pure value in this case an integer and it's going to map it into a list and these functions show up all the time in real code so like doing it doing a database lookup for example we'd take a user ID and return e may return a task of a user and then we have another function here which is the same as signature and what we want to do is to be able to compose these functions so in the last line of this one you can see that when I call this one I'm taking this pure value I'm putting it into the list effect then I flatmap it and what I get out is this is this flan list again so if we didn't have flat map if we only had map then what we would get instead is this nested list and if you think about if you were doing database query instead of a simple list operation that's not what you want because it's harder to get inside you have to kind of go to layers in to get the thing that you wanted so yeah so flat map is that followed by flatten hence the name and you can see from this time signature that it's taking your result this list and squashing it down to a list and more abstractly it will take F of F of F of a and map it into an F of a ok so now we get to Co things so Co things is not many people talk about Co monads or Co things in general in in Scala books but this book does have a chapter on Co things and it's also good because it teaches you how to build practical functional programs and it covers scale of Z which is very similar to cats but it's pretty much the same ok so here's a comb comonad come on it is it has the kind of the same functions as the monnet and that's why it's called a comer net because it's the cow thing to a mo net and the difference is that all the operations that has have that types going a different direction so the the pure function in my net is able to take a pure value and put it into the effect full world but the dual of that is extract and the time signature of extract is to take something that's already in the impure world and pull it out giving you a pure value so the interesting thing about that is you can't implement it for every kind of object because the time signature is telling you what you're gonna get if you have an F if you have an effect for a we're gonna give you an A so that means that if you have something like a list or an option you can't implement the extract function because there's nothing to you get out of it so that would mean that means there's no valid implementation and because it's a pure function and strictly typed we can't just throw an error or return none so we can't do extract for this so we just don't implement it but we can use the non empty list which is something you get with something you get rid of the counts library you can tell from the name that non empty list is a list of things can't be empty so you can't make a none empty list with nothing in it and you can't take you can't take everything out of a non-empty list it just from the types it just doesn't let you do it so the extract function for non empty lists could give you any members of the list but just to be deterministic it will it's implemented to always give you the head of the list so in this case you just get the one so this slide is about and flattened so anvil Aten is not really a co flat and it's not really part of Tacoma Ned but there is an unflagging on flattening operation in in the coma Ned CO flat Muhammad so this is just illustrative illustrative to show you how you would implement it so when you flatten something like before we find a list of lists into a list Co flatten is the opposite what we have is a flat list and when you want to inflate into a nested list so where does that magic extra stuff come from what you get is when you this is the cat's implementation of Co flan and when you get out is you get the original list and then you get the tail of that and the tail of that and so on until you when you got one let one element left so it's giving you a nested non-empty list so that's where the magic data comes from and when you implement Co flan for your own custom data types you can come up with different ways to implement this idea of expanding out into a new level of effects so here's an example of using Co flat map so remember that the flat map was a flattening operation followed by a map what what Co flat map does is first it does that and flattening operation that I talked about and then it Maps a function which collapses that down into a list again so in this case you can see we started off with a list of these numbers and then the function we pass to Co flat map has the signature of being an effect for a being mapped down to a pure value so in this case we're taking a list and it's going to be each one of these lists that we got from our from our Co fine and then we just get the sum of that list so you can see that the type signature is going from effect for to pure so essentially we have this inflaming and then the flattening is done by the function that we passed in so we'll type all the category theory things have laws and one of the laws of Co monads says that if I call extract if I pass extractors the function to Co flatmap on a thing then I should get the identical thing back so you can see that I work here and that kind of illustrates why we did this kind of weird thing giving you the tails of the lists because that makes the laws path it makes this a little pass so conceptually what we're doing is we're and flattening a list do it to the list in all of its tails and then we're getting the head of all those lists which which is the original list okay so now we come to like a practical example of how you would use a comer net in the wild so I made up this data type and this data type represents a two-dimensional array and we're looking at a particular row and column of it so we store the we still this thing called a focus and it's just a tuple so this represents a row in a column of the array and then we store this grid which is a 2d vector of we can parameterize this later so it can be integers or any type you want so yeah so to use comment we need to implement the command add instance for this new data type so we have to think about how we would implement extract and Co flat map so extract is easy we're just looking at a 2d grid the focus point is the point we're looking at so we can just say extract that value from the array and that's the extract function Soko flatten is more interesting so so what you're looking at here is a focus grid of focus grids and the way that it's the way that it blows out is we're going to look at every point so the kind of out-of-focus grid is just focused at the origin so that's this zeros area and then each of these focus grids is just the same array as in the original but we're looking at all the coordinates so you can see this one is looking at 0 0 and then you have 0 1 0 2 so that's the top row of the grid so essentially the unflattering is letting us look at the whole grid one thing at a time so what uses that well it gives us this it means the type signature that we're going to pass the co flat map is going to take a focus grid and return a pure value so that means that we can we can build functionality that requires to looking at something from a broader context and then mapping it down to a more narrow context again so in this example I make a box filter so a box filter is kind of an image processing technique where you just take a grid of all the pixels around a pixel in an image take the average of those and that's the new value for that pixel if you do that to the whole image then you can you can filter the image out so there's the original not my artwork and then we're going to blur it with them with the parameters 5 so this is basically agree Oh 5 pixels and that's 15 so it's more blurred but you can see that we've we haven't written much code here we've just got this one function and then we've got the the actual algorithm of mapping over the grid is encoded in the coma incidents that we made you can also compose these things together so another simple transformation is to do mirror mirroring of an image which just means if I'm looking at a particular pixel you can just look at the pixel mirrored down the middle and that's the new value of my pixel so you do that for the whole image and it will mirror it horizontally so in this example we've first filtered and then wear it horizontally just by composing these functions and these Co flat maps in a sequence so is a more involved example it's a bit more complicated but gives you an idea of you can use all of the things in the council library now we've made this part of the we've made this pure functional thing now we can compose it using all of the things that we've got available in in cats so in this example what it's doing is two operations at once mirroring vertically and mural mirroring horizontally and then it's taking the product of those which is going to give us a new image which has two pixels for every pixel and then finally it blends them using the map which just averages at the mount so again this is all from composition composing things we already did and then you can get this weird image so another example and in in previous talk today we saw Conway's Game of Life implemented in functional reactive style this is pure functional style solving the same problem and the only thing the only change we need to make is to implement this function which takes focus squared and returns a single integer and then we can represent the Conway game of life grid with zero for dead cells and one for living cells and then it's a pretty readable mapping of the Conway game of life rules into into this function that we're going to pass into Co flat map and then down here at the bottom you can see how we call that so we have an initial grid and then we co fly map it with this function and then I'm mapping it to function go prettify which just takes those numbers and turns them into more interesting characters to display so look at the cats library can be as ported to Scala Jas so you can use it in the browser so you can use Scala fiddle so I just pasted my code in here and hooked up some graphics now you can see the game of life animated in the browser to okay that's the that's my talk Thanks [Applause] so I think I do have some time for questions if anyone has one when you're calling Co flatten their you're creating a bunch of redundant data there are there implications for efficiency with that yeah that's a good question if you look at that they just structure in the image in this light there is some duplication but the actual array data itself is not you placated it's going to be a reference so there's not a huge amount of duplication but that said I'm not suggesting that you use this kind of structure to do lots of high detail image processing but certainly for it certainly works pretty fast and uses not that much memory in this kind of use case okay great thanks Justin [Applause]