Devreal

Functor, Monad, Applicative, in plain wo...

Event: Scala by the Bay

scala.bythebay.io: Vlad Patryshev, Functor, Monad, Applicative, in plain words

Recording: scala.bythebay.io: Vlad Patryshev, Functor, Monad, Applicative, in plain words

so first like the target audience for this talk if you are familiar with like coke Holmes filtered limits it's not for you the purpose of this talk was originally the target audience were my co-workers who were very recently just playing Java programmers didn't have much clue about what's Kali's and how to deal with it and what Sam honored and they were totally like puzzled by all these new terms so I prepared this talk and I believe this is how you go at this one okay how about now like this okay do you hear me now so that's what it was so if you are familiar with these things which is factor mana duplicative hunter it's not for you but if you feel vague and there are lots of like vague and wrong notions and the explanations being spread around the world so I want to dispel that fog so that's the purpose of this talk just to be strict specific and clear so if you write in scala you know you have parameterize types right so a tab can have one parameter two parameters it can have like a weird parameter which is also parameterised and so on so you can write something like new age whatever so this way you can pass any parameter to your type and so suddenly your type is not exactly a type it's something that depends on other things so it's like a function take a type return another type so we expand this and find specific specific cases of these parameterize types that satisfy certain requirements that very very good from mathematical point of view and from programming point of view so functor functor is a type we provided with a map of a function so map depends like see we have a trait f and it depends on type X but map depends on another type Y and map takes a from whatever function from X to Y and produces a value the result would be a value of type F on Y so now F Maps types like take a type X and returns gives us a type f of X but also it has a mapping from functions to functions so here we have like we have a function f and we produce a value F of Y so for this mapping of functions to be to give us a factor we need two properties one this functions pretty preserve identity meaning if f is an identity from X to X the result is also an identity and it also should preserve composition so I write this and then you probably know what I mean we apply F to a function to a value then apply G to the result of applying F so like in more verbose mode it says it seems it says like apply F and then apply G so the result of mapping would be would be this apply map of F and then apply map of G and map of identity is identity on F so you know examples list right or set so we if we have a value F S which is a set of like three things so s is what is by default is immutable right right and it's serialized like this is displayed by rappa like this and we map this s with this function that takes a string and take the first L the first element of the stream so with that first well strings are sequences in Scala so it just takes not the first element but the segment consisting of one character so the result would be would take all values of s and produce what a string a string a string a but we have set so a is equal to a and is equal to a so the result would be just set of consisting of just one string a so see it's not like element to element producing like from initial values the like the result values we have a still an instance of a set well the fact that we had the result is still thing is not essential we could as well take like drop one and then transform it to number so we would we would have numbers like 1 2 3 so what's essential is that we had a set and we produces that and it doesn't have to be one-to-one correspondence so we had found a defined like this map cans preserving composition and identity right so if we have two factors their composition is also a factor so if we map F using G and then map F using F so the whole operation is taking an F of G of X and producing F of G of Y so suppose we have a set of list of strings and we transform those things to integers so as a result would be a set of lists of a integers so we do that mapping but that mapping goes inside so that's how it is that's why it's a factor and for it to be a factor it also should preserve composition and identity to see that composition preserved like the first component does preserve it and then the second also preserves it so the composition does preserve it and the same ways identical both are preserved step-by-step so that's it about factors but not everything is a factor here's a funny example define it just a parameterised type on X like this like a type of functions from X to X there is no way you can define mapping from X to Y like given a function from X to Y you cannot define a mapping from X to the power of X to Y to the power of Y no not everything I can say that that's because of a variance breakage like one argument is covariant or another is contravariant that we are not going there of course fighters like in science in math they can be covariant factors contravariant functors I am only talking about covariant and let's not go into variance so but variance is the explanation why this is not a factor well variance is like this but we can just kind of almost ignore it so f of plus X mean and meaning we have map as I showed before right for instance list of things is a subset of list of a subtype of lists of objects and list of object is a subset of subtype of any list when you refer when I'm saying subtype mean we talked about the different kind of mapping right subtyping mapping so it's a special kind but when you talk covariance in Scour we talk about only this way of mapping thing is an object object is any ref any ref is any but for factors you have to preserve this mattang map it should work for any function so sit I show I showed recently that it's a functor but it's not an easy thing because if we talk about relationship between type and subtype set is not exactly a factor in this sense so here we have some kind of problems and there was a lot a lot of argument and discussion on Scala about like whether set is contravariant whether that is covariant and whether it's invariant currently the current belief is that set is invariant but in which sense in the sense of subtyping so if we have a set a 1 a 2 and a 3 and we do this mapping of identity ok it works right but so if so we'll have a set of any right and we apply identity so that's a wider mapping mapping using function but if you if we try to use mapping in using just subtyping relationship Wow somehow it doesn't work that mismatch and of course a set of strings is not a set of any if it if it were mutable we could add any well it's a non Java problem problem right if you convert a set of strings to set of n is how you can add a number to that but in Java will have a runtime exception Scour kind of doesn't allow us this having factors they have map right so it allows us to use this syntactic sugar and have this kind of you that mapping and produce these things like I would scan over the list of these numbers probably prime numbers right G would run over the list of hellos and we mapped this it's been transformed into map that will call this on all these values so it's a map inside map that that this but well here just we are just painting it so this I believe they also talked about for loops right before this talks right so okay so I'll be fast so instead of printing we could produce a list of pairs like this string and mean by Union this GND by scanning the first list on the second list and map is behind the scenes and it gives us well that what we have we have list one and we mapped that and we have lists to inside where we map the things inside lives to into this pair so the result would be the list of all the possible pairs or is it a list of lists yeah it's tricky so we are getting closer to Monnett but we are not there yet so that was all about phantoms now applicative further applicative factor has a little bit stronger feature than a regular factor so what's an applicative factor for an applicative factor like we have an F F is our factor right we have a mapping we are given a mapping is called app from from the type X arrow Y to the type f of X 0 F of Y so if we had a little list of functions we can map a list of X's whatever into list of wise how we have like 10 functions we have some numbers so how many results we will have probably 100 right so that would app that by default but there there are other ways we can zip them I'm not going there alternatively instead of this we can redefine applicative factor like this because our category is a Cartesian closed we can redefine it instead like this call this method and all so define the next and white and map pairs x and y into F on pairs so we have a list of X's and a list of wise and we produce a list of pairs x and y and why is it possible well because we do just carrying occurring or anchoring in this case we do aren't carrying and get this one so having this definition in this definition they're equivalent like we have a having a list of two functions F and G and a list of numbers 1 & 2 so the first way using app we produce functions and numbers we produce a list F applied to one F applied to two G applied to and reapply to two so there these are all possible combinations or using this and also with all these things cause if they think for like having a and B probably strings right or whatever values a and B are we have two lists and we produced a list of all possible combinations yeah oh yeah yeah yeah so if you have a list of lists it's a typical thing that you need you want to flatten a list of list like in many cases you have a code that produces option of options of options or a list of lists of Lists and in a more like tricky cases option of Lists or set of lists only subset list of options then you have to somehow simplify that code the simplest solution is you have a list of Lists right and if you like this for magically you produce you produce just a list of its elements it's it's flattening of a list so Amanat is what allows us to do flattening Amanat is a factor that has a flatten features and has a unit a unit given a value it produces an instance given a value of type X it produces an instance a value of type F X for instance like if it's a list it's a singleton if it's an option so it will be some something and flatten is when you have a list of Lists you flatten them when you have an option of options you flatten them but we should not think that moneth are always containers that's a popular belief and it's not true I mean it's it's not always true so but what we need in Amanat we need these features these these properties and we also need some features like flattened deals correctly with units and flatten of double flattening if I have F F F X so you can do flattening inside or you can do flattening outside doesn't matter if you have a list of lists of Lists right so you can first flatten the list outside and to this list of Lists and then flatten again and produce plain list or you can do for every element apply map of flatten and flatten inside and then flatten again so for Amanat it should be the same thing again like what's flattening for lift well if I have a list like this list consisting of list 1 2 & 3 and empty listen 4 5 6 the result of flattening would be this and this is the unit right a singleton list a popular alternative definition of mana is through flat map from like categories point of view what's flat map apply map and then flatten so that what it does right so we instead of like rewriting them separately suppose we have some data that are of different types so first we do mapping and then we flatten it so like take all the people probably in the world and heavily stuff and for each person list all that all of the person's self we don't have the lists here but maybe like sometime in the future and so this way will produce a list of all cells of all humans and the operation is behind the scenes like if you if you were here and listen to dig so that's how it's represented like yeah when the sugar we take list of all people and flatmap with the function called list cells and why this flat map works properly because it's am honored so here I'm honored loss if M is a month then we have unit we have flattened and if we have applied unit to flattening oh yeah we have a monitor take a unit so we'll have mm right unit adds one more M wraps it like me if we have a list it gives a single term so we apply unit to MX and then flatten it will be the same MX and if you have M X like list of lists of lists right and if we map it on a my max like inside so if we do flattening inside and that so we'll have mm X and then flatten again it the same as if we were flooding outside so this way if we flatten this em with this M will have mm X right and flatten again the result is the same here's an example list of list of lists of way and we can flatten in both ways I talked about this already so examples Amana list well your encountered list you know how to flatten lists list of list of lists and it works right since asset is Amanat so if you have a set of sets how do you flatten it Union that's it what's a unit for set singleton set option what's a unit for options some what's flattening if you have option of options so you can do using like you can either use flatten or you can use like flat map with identity or you can write a case match like empty or sum and then produce just one one option option of option you can easily convert into plain option so result I'll skip result stream future all the things have that flattened so we try I give I believe you can buy skip result because that's my class so I'm not talking about my class today so what do you do with try you can match the tribal success or failure and if you have a try and try inside so in case of really you have a failure in case of success what's inside if we have fairly inside so it's failure if you have a success inside success so we extract that success and we have single fixes nullable interestingly it's a little bit like that's basically coming from JAMA but in Java we can also look at this like if it's now so we don't need to like Dynel if I dereferences if you have something and the produces and also you don't need to call the function so that's why people in Java always check for now they do this monadic these pedantic apparitions without knowing what the moment is and what the factor is they just used to it so again monitor is not a container here's a here's an example like take a state monitor that keep state e the left and we throw it this dice well because it's a monitor statism honored right so we can so it has map because I'm honored is a factor and it has flat map so we can throw dice twice through here through here well the result would be what we threw like after two times so we will have these two numbers start with the knowns she'd do this this is a function two dice throw dice two times the result of throwing will be a pair of integers like this with this but it's not exactly what that it's not a container it doesn't contain anything you throw again and the result would be totally different so it's just something that keeps the state but changes it on every throw so how about composing to Mona's like we have one more not at least in another manner like I said so can we we know that the composition of two factor is a function a factor so that's cool right monads are not that good the problem is we need the flattening right so we have mana G and mana DF and apply again G and then F can we flatten it to have gee generally speaking no because see we could flatten F with F to F we can flatten G with G to F but how can we do this transformation like swap gnf to F of G no way can we transform a list of sets into a set of lists how we have like set ABC and then set one two one two what list do we produce we don't know we can probably go the other way like we have a set of lists and we can try all combinations yes but list all elements of a list of sets so it's well it's it's hard to tell what exactly it is so list of futures and future of lists it works one way but it doesn't work another way and I wouldn't say I know which way it works yeah well this we can do right so we can like wait and kill all the things all these futures finish right but if you have a future of lists can we transform it into a list of futures well hardly and it's basically definitely not efficient if we even invented a no it's not possible like if you have a future of lists right so should we like wait for each individual element keeping in mind that there is something else so all these components of the list will depend on other components so it's it's impossible so lists with future don't commute so that's why in languages like Haskell Scala whatever people invented tons of so-called magnetic transformers so they invent like here the transformer so having a list of set we produced by this transformer set of lists or having a set of lists we produced by this transformer a list of steps yeah but we have to keep in mind they are not given to us by default they are not given us like for any possible combination of Monarch so you saw that applicative functor before right that had like this interesting feature we can transform pairs into pairs of values of front of factor into a fighter on pairs or we can transform a function into another function some moniz are also applicative there is a belief that like in some categories in some languages every monitor is applicative well that's a bad belief because it really depends on pretty like three key features of that language and once you change the language a little bit kaboom it will break it's not so in categories in general settings you can look it up on Matt Overflow I guess so not every monitors applicative but if it's applicable it's a if it's an applicative function it's called strong monad and what's good about strong no not you can run them in parallel like this so suppose we have this supposed ask name is something like that better than option so it either returns the name or returns description like a result class returns the description or failure because of this and that so it's like try and suppose well try is not applicative but suppose there's another function SSM that also either returns a good result or returns failure and we can do this also on that stuff why can't we can do it because because it's applicative because this monitor we build it build it strong we have this operation and also for the monitor generally speaking a mono doesn't have that so in this case we can write this kind of loop and the whole loop is like this we find nameless NSSF then probably we find the company name and we produce a new employee with this name this assassin and this company what happens if we couldn't find a name we'll return an error saying that I couldn't find a name but if you found this assume it's a cake if we couldn't find name and it says we couldn't fight if he couldn't find a name and if we couldn't find SSN either the result of this and also will produce us 2 error messages a name isn't found named not found as a sin not found that's how compilers work a compiler that Iran doesn't give you the first error and then failed right it shows you all possible errors because it works like this and also we try to do as much as possible so we run these things in parallel ask name and ask SSL when we try to return both results if we are successful then the next that's monadic thing the next operation is extract company name I don't know where company name comes but where we could as well fail on company name if we succeeded here and failed here will have only one error oh no company but if we failed here like on both name and system we will not bother to go for company because that's flattening in optional result class will not go deeper will not call it well we do have a failure so but so this is a combination of applicative features and magnetic features in this world well some moments are naturally applicative like lift well because you can zip like here we have a bunch of functions and a bunch of whatever values and we you f of X so we don't have to guess list actually if you look closer there are there is not a unique way to turn a monolithic if if even if you can't turn Feliz here will have all possible combinations of functions F and values values X right another solution would be to zip like take the first function and the first value take the second function in the second value there's a puzzle or what do you do when like the first to list and before the other list and so in in Haskell the kind of bypass this by generally like expecting a list to be potentially infinite so they produce some solution but in Scour we are kind of we don't do that how Scala is not Haskell but again if instead of lists we had streams yeah we could zip streams together that that's okay so meaning applicative et monadic strength is not given to us by default it can it can vary so it's it's up to us to choose what to use so that's it thank you questions should I go back to the first slide so like functor tap you with the map applicative finder we have this mapping or alternatively we haven't also the converts Cartesian product with the F on Cartesian product monad is a furniture with flattening in units and throne bonnet is an applicative factor that is also a Monnett that's it so these are the definitions and they can like look through them and basically not pay attention to those like additional stuff yeah yeah mono transformers yeah the question was can I say something about mono transformers since not every to monitor produce after composition Amanat we have to find the way we make find the way to make it Amanat so how do we make it look at this like FG FG we want to transform it to FG right for that if we only ever only like it to have F F G G then F F flattens to F GG flattens to F and that's it but the thing is here we have this like something that breaks our commutativity FG inside GF inside so if we had a transformation from GF to F G then we are lucky right we have FG FG transform the thing inside into FG so we will have F FG f FG G and then we flatten them individually so they think the transformation from GF 2 FG is called magnetic transformer so for any given pair like there should be probably like a big table somewhere magnetic transformers for camp for all combination like option of Lists - list of options or list of options - options of Lists set of futures - future of sets well that's hard you know future of self to set a future and so on so all the things they're kind of a popular topic and people come up with well as soon as we invent a moment right you have to figure out how my new monitor can interact in trop with lists how can I deal with sets so it's it's a typical thing that like especially from your programmers so they produce this stuff like oh we have like cool Italy but I cannot write this for because I cannot transform you cannot write like a for loop where the first element is a set and the other one is option well option is iterable so it transformed to interval so intervals you can flatten but if we have the first row as a list and then like statement or like those dice throwing or not state but like future so we would be puzzled how come I don't produce the right result so that that's a typical question by Java programmers your monitors are not good because they can act like convert a list of sets of futures to a future of sets of lives yes you cannot because that's its laws of nature that not the problem of monit that's like a Rubik's Cube you cannot like turn one side and then the other and then one back and there at the back and produce the same thing that's that's we give that the properties of the space where we live in yes yeah yes so the question was can I give like a nice example of using applicative phantoms so this is basically what like in the previous company in health expense you know in my current company I used Java six so so what we do we're like open a webpage and try to extract data from there so the data are you know be explanation of benefits so we look up like patient name patient date of birth like the claim number the amount and so on and we look that stuff up if we find everything on the webpage that this is okay like we process it and that's a good we're good but what if something is not found we cannot just like throw into the logs something not found right well people do it all the time like in Java specifically but here I want to have the list of all the failures so we can say ah patient name not found or maybe like we found the patient but we have five patients with the same first and last name David Smith probably or like the date of birth well found but wrong well in I kept okay I'm not working there anymore so we have 20 people born before 1 during the days of Julius Caesar so meaning like the first two digits of their numbers are missing so all the things they can be listed because we have a classical result so result it's either good with the value or maybe like some values or it can be bad with the list of failures those failures actually also contain stacktrace so again like if you are really curious about like what's going on so you can done stack trace of all this error that happened so instead of just ask name and ask SSN we have like a bunch of these also we can have a list of this like we've tried to get like value number one while we value number two and so all and so long and so on value number n so there is this thing called reversible I believe Adelbert was talking about reversible like to talk before right so we traverse it and we either produce lists of good values or we produce a list of error messages so that's another feature of applicative factors you can't reverse it so that that would we get successfully a bunch of Java programmers got into it and I remember hearing them saying after like two or three months they're switching from Java to scour all right I want to write stuff a monadic style so that's how like if you provide good tools and explain these things they will be doing it magnetic style and it's pretty efficient basically the purpose was to make sure that we don't need so many developers but we need the stuff work like I know how many 400 a service right something like that yeah so I would say like it was successful in our company thank you [Applause]