Functional Programming with Effects by Rob Norris

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay so our goals for today don't panic the so I'm gonna go through a lot of code today and a lot of code manipulation and drive a lot of ideas from first principles so the goal is not to follow every single step that I make but to understand that what we're doing is very systematic and there's a big picture that all this stuff fits into and it all sort of clicks together once you understand how to take the individual steps the more you learn about this stuff the more directions you hear it coming from the clearer the picture will become and you'll start to be able to fill in stuff on your own we want to understand what functional programming is and we'll spend a lot of time talking about that gained some insight into the way functional programmers think about things and that's important you know the mechanical aspects the technical aspects of functional programming are not hard I mean they're they're almost by definition very simple but learning how to apply them to different situations is hard and it's just helpful sometimes to just see somebody manipulating code like a functional programmer would to get into the sort of the swing of things understand why monads are useful and where they come from so this is a talk about monads if you already know everything there is to know about monads if this is too easy for you or if it's too hard for you or you're not interesting for whatever reason there are two other really good talks going on right now so if you if you decide to change rooms I will not be offended we're here to learn so let's be sure we keep doing it and I want everybody to be inspired to be curious about functional programming umm this stuff is interesting and it's fun and it will make you a better programmer if you learn it even if you don't use it every day it's a helpful way to think about things okay so people are interested in the kind of work that I do I get a lot of questions about it so I'm going to share some pictures with you today from work so all the pictures that I'm going to show you where we're we're taken by by our telescopes will start nearby this is the Gemini North telescope it's on Mauna Kea in Hawaii it's about five thousand miles from here our southern telescope is in chill it's about five thousand miles south of here the software that I work on helps astronomers use these amazingly complicated machines to do science and we have a really small team we have a lot of software and we have found that functional programming has dramatically increased our code quality and maintainability and it's a lot more fun to I mean it's okay to have fun at work so I do this in real life and I really believe in it and I'm happy to help people who are interested in learning so I'm easy to find as I said reach out and talk to me if this stuff interests you alright let's talk about functional programming what is it so at the very bottom we just have values we have things and because this is Scala it's a typed language we classify them into different types and we can think of types of sets so in type theory we typically just treat types the same way that we treat treat sets and then we have functions that map values from one type to another and notice this is a mathematical function that I'm talking about it Maps every value in a to some value over in B okay exactly one value of R in B it's not necessarily clear from the picture but that's all the function does okay it doesn't increment a counter doesn't check the system clock it doesn't write to a file a function is a mapping from values to values and that's it so let's preserve some things about this so functions like this are said to be pure and the output is determined entirely by the input and nothing else and consequences of programming in this way are that evaluating expression will always give you the same answer no matter how many times you're evaluated so that means that we can always inline a function call and then we can always factor one out because we know it doesn't matter how many times we evaluate it it's always going to give us the same answer and more generally we can always substitute a variable for the expression it's bound to so we can we can factor out any common sub-expression or we can inline any variable to what it's bound to and this property this ability to do this two expressions is called referential transparency so let's look at some examples of that so the question here is are these programs the same we have a valet that's bound to some expression and then we compute the pair of a and the second one has just in line to a and we're computing that expression two times and the question is are those the same program and the key observation is that in functional programming the answer is always yes they're always the same program okay and ultimately the benefits of functional programming all flow from that fact everything we do is built on this ability to perform substitutions we can manipulate our problems our programs symbolically like mathematical objects without fear of accidentally changing what our program does but in general depends this is Scala and we have side effects in Scala so let's let's look at some more examples what about this program where a is 42 are these two programs the same what do you think yeah I think they are what about this one are these programs the same no all right one of them prints hi once and the other prints height why so you can't swap one for the other what about this one we're giving an iterator and you're calling next no no all right so the second one advances the iterator twice there's internal state that's being changed when you call next what about this one this one's a little trickier listen depends this is pure as long as he never mutate the result is never as long as you don't mutate the array in some other part of your program it but if you do have code later on that mutates one and not the other then you can detect the difference between these two programs so there's some subtlety to it and in Scala you have to be careful and you have to think about things the compiler doesn't help us a lot so let's review this real fast ever expression your program is either referentially transparent it has the substitutability property or it's not and if it's not we call it a side-effect it's either one or the other every expression so this is a syntactic property of your programs okay so saying something as a side-effect is really kind of an indirect statement about runtime behavior what we're really talking about is whether this inlining and factoring out substitution is legal or not and if you think about side-effects in those terms I think it's pretty easy to see looking at a piece of code whether something as a side-effect or not instead of trying to think about what the program is doing just say are these the same program under this transformation and we care about substitution rules for expressions because in functional programming this is the world we live in we are out of the world of statements we're in the world of expressions functional programs are expressions running a functional program is the process of reducing a evaluating expression to get an answer we reason about our program is by substitution and by reasoning I mean the same way we would reason about a mathematical expression we move things around mechanically and algebraically and then we build larger programs from smaller ones by composing them together ok and because the only thing we have available right now our values and pure functions let's talk about function composition okay so here's the function that we had before and now we can introduce another function from B to C and we can compose them end to end so if we do F and then we do G we have a new function called F and then G okay so how do we define this and then operator in Scala so here's how we could define it it's a method it has three type parameters it takes a function from A to B one from B to C and it gives us back a function from A to C and the implementation is just takes the a and applies G of F of a it's very straightforward and in fact that's the only way you can write it a pure function of this type that will type check and because we're in the world of expressions and we're thinking mathematically we see an operator like this we might ask questions about the properties of this operation for instance is it associative if you have F and then G and then H does it matter where the parentheses go in that expression and if we can show that it doesn't matter then we have another substitution we can add to our library of tools so how do we figure this out let's do some equational reasoning we'll use the substitution model and just expand things out and see what it looks like so here's the right associative expression so what we'll do is we'll inline the and then the outer one and then we'll inline the inner one and now we have B to H of G of be applied to F of a so we can just substitute F of a in and we get that and that looks right to me let's look at the left-hand case well in line the outer end then and then the inner one and again we have H of this function applied to a we can inline a and we get the same thing okay we've proved it we proved that function composition is associative by doing this reduction and coming out with the same the same program and we can do the substitution now anywhere in our program right purity gives us this ability to inline in fact our things out and we can use it to drive new substitutions that we can use later on and this is where FB becomes really powerful what else can we ask about this it's a binary operator so maybe it has an identity so maybe my conjecture here is that if we have a function that does nothing but return what you give it you can compose it with any other function and the net effect will be you haven't done anything so let's try that so we have this ID method that takes a value and returns it let's see if it's an identity on the right so we in line and then we in line ID we we apply it to f of a so a to f of a is just F so right identity works and similarly we can inline left identity and also get F in case we have this other substitution a pair of them if you compose with the identity function on either end you can just forget that you've done it and get rid of that composition because it doesn't do anything okay so now we have functions between types we have an associative composition operator with an identity function at each type okay and we've proved that it's true by function or by by by the definition of function composition because there's only one way to write it all of this follows from the types which is cool so it turns out there's a mathematical structure that describes the situation exactly it's called a category ok category has four things as objects in this case they're Scala types it has arrows or morphisms in this case they're pure functions it has an associative composition operator which is our and then operator and it has identity arrows at each object which we've defined by our polymorphic ID function that gives us an identity function for every type okay well right why do we care it just it turns out that mathematics is useful so by identifying these connections between types and programs and mathematical structures we've been able to do a lot of really cool stuff in NFP and I think one of the benefits of programming this way is that the connections with mathematics are much more apparent the gap between theory and practice is quite narrow we can apply these ideas very directly and this is where we started to see the benefits of functional programming we can be more confident that our programs are correct because we can say very precisely what things mean and then we can refactor confidently because we have these transformations that we can perform on our code that we know will not change what the program does it might make it easier to read or more efficient but it won't change the values that are computed so that's very powerful and that's kind of the value proposition for functional programming it helps our programs start off correct and stay correct as they evolve the second point is much more important in my in my mind so but in exchange for what we've just done we lost a huge amount of expressiveness right it's a much weaker language to describe our programs so how do we square this with with what happens in the real world so partiality functions always have to return an answer and we don't always do that in Java you might return null or something right sometimes there are exceptions sometimes we can't compute a value and we have a reason why we can't the we encoding and an exception functions can only return one answer but sometimes you can compute multiple answers things like things like dependency injection you have this non-local scope that can inject things that that will change the behavior or they'll affect the behavior of your functions and doing that prevents you from reasoning locally so that's a problem but it's useful so how do we deal with that logging for instance it's a side effect the whole point is to tell you about when things are happening but in functional programming this we don't care when things happen we're just computing values so what do we do about that immutable state obviously there there are a lot of things that are just easier to express in terms of mutable state an imperative programming generally sometimes it's easier just to say do this do this do this do this and not think about things in terms of chains and branching function calls so how do we recover this expressiveness and that's that's really what I want to talk about today so let's take a little pause there's some pictures from work does anybody want to guess what we're looking at this is IO it's one of the moons of Jupiter and it is violently volcanic all those flares you see are either volcanic eruptions or lava lakes and the the big lava lake in the middle of the larger images is so big they give it a name they call it Loki which is pretty cool and this is all happening right now about 390 million miles from here okay where are we we have a programming model with pure functions and function composition and we know how to reason about that we've done some reasoning with it and we're comfortable with it we've left behind a lot of expressiveness that we would get in Java or Python or or whatever and the way we recover this expressiveness is by using effects okay and effect is kind of a vague term it's okay we're kind of trying to describe something that's outside what the language can talk about and it should say if there's one thing you take away today it's that effects and side effects are not the same thing it's unfortunate they sound the same effects are good and side effects are bugs so just remember that and you'll you'll be okay so what I want to do is talk about the six effects that you sort of learn there's sort of the first six that you put in your toolbox when you learn functional programming there are a ton more and there are lots of ways to classify them but we'll start off with the the basic ones that you'll get a lot of mileage out of immediately what we're gonna do is we're gonna look at six effects and talk about what they mean and what they have in common and we'll try to reach a description that's very precise about what they have in common all right so let's talk about option we're all Scala programmers we know about option there are two cases you either have none or you have some value and if you have functions like F and G the intuition there is what we're encoding is functions that might not return a value okay it encodes this notion of partiality so we get that expressiveness back by computing values in option the problem is we can't compose those functions together anymore what we would want is if you have an 8 and option B and a B to option C and you give it an if you were able to compose them together and give it an a you either get a C out if everything went okay along the way or you get none if there was something that couldn't be computed along the way if you could somehow compose those effects together but we don't have a way to do that so let's go on everybody has seen either it's another very common type from standard library we either have something on the left or something on the right it's very similar to option but the intuition is we have computations that can give us a reason why they don't didn't compute a value so this gives us this notion of exceptions back and if we were able to compose F and G together the idea is either we would get our C out if everything worked okay or we would get an error back on the left hand side and we would get the first error that was encountered in during evaluation because as soon as there's an error you don't have a value to pass on to the next function that you've composed okay but we can't do that we don't we don't have the means to compose these functions intend yet let's talk about lists so this is an inductive data type it has an empty case and then a case where you have a head followed by a list and I think everybody's probably seen lists in in Scala the intuition we have a functional programming is a little different than the way you might normally think about lists it's a way to think about a kind of non determinism where you can a function that can produce many answers and if we were to compose these together and to end if we were able to what you would get if you have the ADA list be composed with G list with Vito list see you get every possible seeding that could be computed from those two functions so the computations that you perform with lists sort of give you a just every possible universe of answers back but we don't know how to do that yet okay let's talk about reader this is a new type for a lot of you probably but it's a very simple type we just have a we'll call it in its it's just a wrapper for a function from some environment type e to an answer a and so if we have a function that goes from a to reader of config B the intuition there is that we're we're computing a computation that's dependent on on some value that we don't have yet so let's show it looks like an example of that so we have this path method it takes a string and what it returns is a reader of host to string and when it once it gets the host it can construct our URL so the the the idea there is that this computation is something that is awaiting awaiting a configuration to be passed in before it can finish its work so what this gives us is dependency injection okay we have a computation it's all ready to go but you've got to give it the the configuration before it can actually compute its answer okay and if we had two functions like this composed end to end the idea was would be you would get an a2 reader of config C and you compute that and then you pass in the config and it gets piped through all your computations and everybody gets to see it on the way to computing a C but again we can't compute that if there's a reader there's got to be a writer I'm actually going to skip writer in the interest of time it's not super interesting because I want to talk about state this is the hard one and it's a really interesting one so state is another wrapper around a function what it does is it takes some input state and it computes an answer a and also a new state okay so the idea here is that is this if you if you have a state transition if you have some some mutable computation you can model it as something that takes the initial state does something and returns the answer along with the new state and you pass that new state along to the next company computation and that's what our notion of composition would be like and we can look at an example of that we have this greet method that takes somebody's name and returns a state of a counter and a string so what it does is it will greet the person and tell you how many people have been greeted and it will return the new updated count so we can create that computation and we can run it with an initial value of 1 or initial value of 20 and we get the string back and in the new state in a pair if we were able to compose them we would be able to thread this state throughout our computation and it would be entirely excellent but we can't do it we don't know how so the question here is what all these effects have in common they look they look quite different but all of them compute some answer and there's some ancillary stuff there's just some extra kind of machinery associated with the computation and this is what we call an effect but it's still very vague so let's let's try and be a little more precise about it so let's observe all of these types have the same shape it's on f of a for the types like either or read or write or state there's an extra type parameter on the left and we just fix it to something so reader of config is an effect a state of int as in effect okay and and kind of the punchline it's not very satisfying but in effect is whatever distinguishes F of a from a it's just that extra machinery that's associated with the computation we will sometimes say that this is a program in F that computes a value of type a so we will talk about computations or programs and it might seem weird to think of something like option of string as a program but if you think of something like a reader or state that actually has a little function that's running inside of then it might make more sense to think about it as a program but that's a good general way a generic way to talk about these values but our problem is as as we've said they don't compose so what we have this function that goes from string to option care it just goes and tries to find the the character at index 10 which might fail and then one that gives the what does it do it gives the the character code if it's a letter otherwise it doesn't and we can't compose those into end so this is kind of an issue anybody want to guess what this is no guesses there's a Pluto and its moon Charon these are the sharpest ground-based images ever taken at least at the time they were taken and this is happening right now about 4.6 billion miles from here it's a long way okay so what's the problem the issue that we're dealing with is that effect full function don't compose we've found ways to recover a lot of the expressiveness that we gave up but we've lost function composition in the process so what we're gonna try and do is recover that as well so let's look at our model of composition from simple functions so here's our category of Scala types and functions and if we understand the category rules we understand everything there is to say about function composition so what we can do is frame our question about effects will affect all functions and a little in a different way let's just say what would it take to make the same rules apply to effect for functions let's just change our diagram so everywhere we have an A to B we have an A to F of B so I D is a to F of a instead of just a to a and so we don't confuse ourselves let's let's rename these operations so and then we'll become this thing that looks kind of like a fish and then I D we've call it we rename to pure the intuition there is that it takes a value and it turns it takes a pure value and it turns it into a program that computes that value so here's the game the game is we're gonna make an eclis write down what this means in Scala and just follow the types and see and see what we have to do and because the behavior depends on a particular F we're gonna parameterize it's going to be type class parameterised on F okay we'll call it fishy it's parameterised on some type constructor F so we have two things that we need to implement we have our identity a - FA and we have this composition operator it we can if you look at the the fish operator we can actually start to implement it we know we have to take an A and we have something that we can pass the a to so we can say F of a and now we have an F of B and a B to F of C and what we're on one is an F of C so can anybody think of something they've seen before that has that signature i'm standard library somebody said it flat map looks like flat map to me okay so it turns out this fish operator is kind of something we can derive later and what we really need to define is flat map okay and we can create for instance a implicit class that adds the fish operator to affect full functions by wrapping a function from A to F of B and then adding a method that takes a be def of C along with evidence that there's fishy behavior for this F and then we just delegate to it so that gives us our that gives us our fish operator we can define an instance of this type class for option so we need to define pure and we'll just say sum of a is is is our implementation of pure and flatmap we'll just delegate to standard library flatmap and now we go back to our functions that don't compose any it don't compose with and then but they do compose with the fish okay so we've solved that problem so we can construct this this function and we can apply it so we apply it to foo there is no tenth there's no character to index ten so we get none if we apply it to the longer stream with string we get the character code for the Z or the another Q I don't know which for the U and then if we change the you to something's not a letter we get none again so the the the failure mode exists in both places across this composition okay so that's cool we have these operations and they work but the thing we've forgotten about is the rules so here's our diagram again and what we've forgotten is category laws say we need these three things we need left identity so pure fishy F has to be F F fishy pure has to be F and then associativity has to hold those compositions have to have to mean the same thing so what does this mean in terms of flatmap let's expand these out and see what we're looking at so pure fishy F we'll just inline the implementation of fish so it's pure a flat map F we can expand the other side out to a de FA to kind of the kind of matchup where that's just a de expansion and then we can we can treat this a as a kind of a free variable doesn't matter where it comes from so we have this rule pure a flat map F has to be the same thing as F of a all right let's look at the right identity we can expand this out in a similar way and then we can treat this a as a free variable doesn't matter and F of a we can treat is just any any free variable so this M flat map pure is the same thing as M means if you flat map and appear nothing happens left associativity same thing we can inline the outer one in line the inner one and substitute so we get a a flat map G flat map H all right and let's look at the right side and these have to be the same so we can inline the outer one in line the inner one substitute okay and now we have F of a flat map G flat F H has to be the same as F of a flat map B 2 G a B flat B so so in Scala this isn't super apparent but it's just the associativity rules it's just where it's just the order in which you do the flat map and again we can just treat that as an arbitrary value okay so we have these three rules that we've come up with just by looking at the category laws okay and this isn't something arbitrary so that's the point I'm trying to get across these things followed directly from the category laws and they're analogous to the rules for just simple function composition that we drive to the beginning of the talk I will tell you what we've been doing the category that we've been looking at is called the closely-- category F so when you hear functional programmers talk about closley blah blah blah it's just arrows from A to F of whatever it's an intimidating name but it's it's a very simple idea in order for this to be a category F has to have this fishy behavior that we've defined and this fishy type class that we divide it we came up with from nothing is called monad that's right and remember would also drive the Monad laws okay we got the whole thing everything you can say about monads is on this slide okay and it all followed from the rules of category theory the rules of composition that we learned in the first five minutes of talking about category three so now you know where they come from and you know why they're useful because they give us back function composition for effect 'fl Fortin to remember or to note that unlike the rules for function composition which are necessarily true from the types the Monad laws and type class laws in general do not follow directly from the types Scala is not expressive enough to do to prove that so when we implement a monad instance you can't just satisfy the type and call it good you have to run tests you have to ensure that these laws are met okay in Scala we do this by property based testing and there's a pretty elaborate set up in cats that allows you to do that very simply which is which is great and Chris Phelps right here has given a talk on this and has promised he will give it many more times so it's something that you it's important to learn okay so we have pure and flatmap and and something you may remember from standard library anyways everything that has flatmap always seems to have a map too so it seems like probably we can add map there it turns out that map is defined on an even more general abstraction called a functor and all monads are functors so the structure actually looks like this monad extends functor and functor has this map operation I don't have time to define categorically so you'll just have to trust me that this is the case but we we've already said that we've completely defined what monad means so we should be able to find map in terms of pure and flat map okay and we can so that type checks and basically instead of you can't you can't flat map F but you can flat map F if you lift the result by calling by passing it to pure so this type checks but is it the right implementation we don't know all we know that is that a type checks so in the same way there was a composition and identity rule for monad there are also laws for functors and I'm just going to tell you what they are we could derive them as we just did but we don't have time and here's what they are if you have something and you map identity it does nothing and then if you map F map G it's the same as mapping over F and then G okay and that's a cool substitution because that's a very obvious gain and efficiency if you go from the one to the right to the one on the left so can we show that the implementation that we wrote obeys this law okay I claim we can and will use equational reasoning again so here's the identity rule so what we do is well just inline our definition of map then we'll inline identity and we'll apply a and then a to pure of a is just pure and we remember that the right identity law says a flat map pure is just a so we're done the identity law necessarily holds okay composition is a little more involved so we have a map FF map G will in line the definition of map and then we'll use our associativity rule to move the parentheses around okay it's it's a subtle change but it's important we reassociate and now we have an expression pure of something flat map something that looks like the left identity rule so we can just substitute f of a in for a on the right hand side and we get this okay and then the left rule a map FN and H will in line what map means in line and then look they're the same okay so we've proved it we prove that if you have a lawful monad then our implementation of map is necessarily correct okay for any Monat at all which is really cool okay so we have pure flat map and map and the reason I want to show you this it's just to show that it's all the stuff builds on itself it's very systematic and they're very precisely defined relationships between these abstractions that we use in functional programming and once you kind of get your feet wet you find that everything ends up being very predictable and very consistent and the ability to lower your blood pressure is a very underrated feature of functional programming so let's look at one more operation and I won't move on here's one called tuple it takes an F of a and F of B and it gives you an F of the pair type of an B and we can define that in terms of flat map this is a an operation from applicative functors which we aren't going to talk about but again I could prove to you that this implementation has to be correct in the same way we did it for functors so carrying on we can find a syntax class and this just says for any for any type that has a monad instance we can give you flat map map and tupple just by a syntax extension and now anything with a monad instance can be used in a for comprehension that's pretty cool anything with a monoid instance and let's add two more derived operations so I call these left shark and right shark the idea is that you're sort of swallowing the value on one side or the other so what this does is this tuples the things together and then throws away the left side or the right side and we'll play around with that in a minute when we look back at our effects so this is kind of cool this is a debris ring it's around a star half of a binary system it's kind of like the Kuiper belt in our own solar system but much much bigger the star itself is hidden behind a mask so the light from the star doesn't overwhelm the dark stuff around it that we're looking at it's getting harder for us to say this is happening right now because the light from the star takes 237 years to get here we're now at the point where we're running out of words to describe the distance this is roughly fourteen hundred trillion miles from here all right so now we know all about monads and let's see what we can do with our effects now let's talk about option again so option gives you a flat map out of the box from standard library but I'll show you how it's defined if we take an option A and an eighth option B we pattern match on the option and if we have an A we apply F to it and if we don't then we pass none we don't have an A to pass along so we have to stop and presumably most of us have used options and for comprehensions so I'm not going to talk about that let's talk about the blowfish operators because they're interesting or the sharp operator so we have this validate method it takes a string and it validates the string is non-empty so it's not empty you get some if it's empty you get none so we can say validate Bob tuple validate dull and we get some of the pair of both because they both are valid if either of them is empty is in the second example you get none back we can validate in the next example we can validate both and throw away the answer to the first one we only care about the second one in the next example we do the same thing we throw away the first one and we get none back the validate with the empty string there is only therefore its effect so even if we don't care about the value that we compute the effects can be important the last example a results 17 is the same thing as a result 15 is just flipped around we flipped the arguments and flip the shark and we got the same thing back which is kind of cool this is not true in general it's true of option because option is a commutative monad okay we'll look at some other types where this doesn't hold okay so what this gives us back is partiality we're programming is if we have something like null or something that represents no answer okay but in an entirely pure setting so we can program that way again let's talk about either again you get flat map out of the box in 212 so the implementation just says if you fix the left side I can define flat map over the right hand side if there's a left value then we just pass it along if there is a value on the right we apply our function to it and get the next either that we pass along so let's look at an example of that we have a validate method now that takes a tag so if the value is non-empty it returns it as success otherwise it gives you a reason why it failed now we can write this method validate name it takes a first name and a last name it validates the first one and validates the last one and it returns a string that that's the concatenation of them okay and notice that we're not mentioning the failure cases anywhere in validate name we're just sort of writing out the nominal case okay so if we run validate name for bob dole we get a write with the string if either is empty we get a message telling us which one is empty which is pretty cool so now basically we have exceptions back okay but this is totally pure let's talk about lists again the the Monod for lists just smashes all the lists together with with with flat map so I'm not going to talk about the implementation for it let's look at tuple it's kind of interesting if you take two lists and two plum together you get the Cartesian product you get every combination which is the way we had described it before it possible answer and the next two examples just demonstrate that this shark reversibility doesn't hold in general if we use one list or the other just for its effect you can tell the difference you get X Y X Y verses xxx yyy this is just to show the commutativity does not hold in general for those operations let's talk about reader so the implementation for reader says I take some environment and I compute a value and then I compute the next reader and I passed that same environment to it so it just threads the environment through here's an example here's our path method again that takes a host here is a second a second method that just tells us the length of the host so now I can write this program that says we'll create a path from foobar and we'll get the name of the host we'll get the length of the name of the host and we'll compute a string that talks about those things and when we run it with Google comm we we find that that environment that Google comm is available to all the computations that we've composed together but we're not talking about it okay so in this prog definition we don't mention the configuration at all okay so this kind of gives us the ability to program as if we have dependency injections a dependency injection but we're really just passing arguments to functions so we have not lost the ability to recover easin locally about we're doing so we get the noise reduction but without infecting our program with this big global scope let's skip writer since we didn't talk about it okay state is the really interesting one so remember we take some input state we compute a value and we turn the output state along with it so to compose these into n we run the first state computation and then we run the second computation with the newly computed state and then we pass the answer to that along I'll show you an example of that so we have this rnd program that's a state from seed to int and what it does is it computes a new random number new pseudo-random number so now we can define a little program called d6 that rolls a die I guess it should be it's actually 0 to 5 it's not it's not 1 to 6 but so we're taking this random program that make that gives you any number and we're using map to reduce it to a value between 0 and 5 and now we can use that and compose we can create another program called damage that rolls to dice and adds two together and returns the answer to you and notice that these are vowels these are not depth these are values we can run this with a seed of 17 and we get 10 as the answer and then this huge number is our next seed we can run we can compose again and and have a program that runs this damage thing twice and we can run that with 17 and take the first part of the answer which is this that string we've constructed okay or we can to pull it together and or use any of these common errors that we've that we've defined so we want wrote this one definition of our nd that understands how to propagate the seed around and then we forgot about it and for the rest of our program we're programming as if we have a mutable random number generator but it's entirely pure okay so I think state is kind of the exit exam for for monads 101 if you understand state then you understand monads and you understand effects and there's no stopping you once you get this so a lot of people find the state monad to be sort of the the mind-blowing thing when they're getting into functional programming so I encourage you to study it okay this is our last stop it doesn't look like much that red smudge in the middle of the grainy image is a gamma-ray burst it's one of the most distant objects ever imaged the amount of energy released was estimated to be three and a half times 10 to the 52 eggs which is a billion billion billion times brighter than the Sun it's a very high redshift which is the only way to talk about distance for things that are thus far away because the universe has expanded so much in the 11 billion years that it took the light to get to the earth the light travel distance itself is on the order of 10 to the 23rd miles so we can call it a billion trillion trillion trillion miles give or take okay Big Finish is that no that is not it this is just 8a the barest taste of the kinds of effects that you can model in functional programming and the kinds of things you can express with monads and monads are just one family of effects they just happen to be really useful because they give us the structure of imperative programs which is something that most people are immediately missing when they move to functional programming so it's good to be able to get to monads because that'll give you a lot of your brain power back so it turns out the operations we've been talking about form a hierarchy of increasing power there are lots of things that have map and slightly fewer that also have zip slightly fewer that also have pure slightly fewer that also have flat map so it forms a subtyping relationship and in Scala we use subtyping so this is kind of what we have we talked about functor a little bit we talked about monad there's also applicative and apply that correspond to a peer and sieve and these are just for families effect of effects and in in in cats there are quite a few more I'll give you a link to this graphic at the end if the stuff interests you look at it find monad find functor and look at other structures that are nearby because they will be similar but different in interesting ways and and it's a good way to start exploring so let's review huh that said review my intent was not to have a back tic at the top so we've talked about functional programming we know what it is and we know why it's useful we've talked about referential transparency effect types we've talked about monads we know everything there is to know about monads we computed it from nothing we talked a little bit about functions as well things that you will hit next if you learn this stuff and want to take another step applicative into reversible functor they're related they end up being very very useful very quickly once you start doing this kind of programming so that is a likely next step for you we did not talk about composing effects so you can stack effects up you may not have a future of option or an option of either and you might want to compose functions that are computing in those composed effects and there are ways to do that but we haven't talked about that today and and there's a lifetime's worth of stuff to learn so here's some resources for cats type level org slash cats is the top level website there's a getter channel the infographic is in my github if you want to orient yourself with all the type classes Scala with cats is a great book it's by NOLA well she's here somewhere maybe not in the rim and Dave Grinnell it's available at underscored IO and it's free and functional programming in Scala which is kind of the master work on this on this stuff in Scala and it's a brilliant book and everyone should read it and that is all I've got thank you for your time [Applause]
Info
Channel: Scala Days Conferences
Views: 17,474
Rating: 4.9428573 out of 5
Keywords:
Id: 30q6BkBv5MY
Channel Id: undefined
Length: 49min 42sec (2982 seconds)
Published: Fri Sep 21 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.