 My name is Adelbert Chang. I'm a software engineer at BOX. I work on the machine learning team. And today I want to talk to you guys about why I like functional programming. So to sort of set the stage for what I'm going to talk about, I'm going to sort of go into the background of how I got into the ideas of functional programming and why I enjoy programming in a functional style so much. And so I'm going to start off by where I got into computer science and where I learned programming. And that would be in college at UC Santa Barbara. So there's an aerial view. And UC Santa Barbara is in Southern California. It's a nice campus. It's where I first learned CS. It's where I first got into math and physics. And it's where I also learned and started really enjoying functional programming. So I went to UCSB in 2010. And so I'm going to start off in 2011 because that's when I really started taking the more interesting classes. And so the first few languages that I learned at UC Santa Barbara were really popular imperative languages, languages like Python, C, C++. And I really enjoyed my courses a lot. I really liked the CS aspects of it. I really liked learning about the theory bits. But then when it came time to actually do the programming, to actually do what I wanted to do, I ended up writing code that looked like that. And so the problem is relatively simple. You say you have something like, I have a binary search tree and I want to insert a value into it. And when you give the algorithm, when you say the algorithm out loud, it's pretty simple. You say, compare the value you want to insert to the value at the root. And depending on if it's greater than or less than that, you go to the left or you go to the right. But in the actual code you write, you end up thinking about all these weird things where, oh, you say I have a traverser. And then I have a parent that's initially unassigned. And then depending on what the value is, I'm going to move these two things in tandem. And then based on some condition, I'll break out of this loop. And this loop is while true. So the condition is more or less ignored. And then presumably you're going to break out at a place where your parent has some specific value. And then you're going to mutate the parent in place and then create the new node. And so the actual algorithm that you care about, I felt like, ended up being lost. So when I went to my CS classes, I enjoyed, oh cool, if we have this thing called a binary search tree. You can implement a hash map based on this. You can implement all these things. But when I actually went to write the code, it became really annoying. And I thought that we had all these extraneous factors and outside factors I had to think about. I wasn't really thinking about the actual CS part. I was thinking more about maintaining this weird state. On the other hand, I also started taking our required physics and math courses. And so these were relatively simple undergraduate level courses. The math was like differential equations. Physics was classical mechanics. So it wasn't terribly involved. But one thing that I really enjoyed was that all the problems they were solving were simple and they were consistent. And so whenever we did problem solving in these classes, I never really thought that I was trying to solve a problem outside of the thing I actually cared about. I was always like completely focused on a problem and I could work with it in a very reasoned and logical way. And so as a sort of motivating example that I came up with in classical physics, we are given like these various laws of motion and I put three up there. And so I did take a little bit of physics in high school and when I first saw these equations, I sort of felt like, okay, these are three equations, three magical equations that I have to like memorize and figure out somehow I have to know when to apply these various equations. And then when I took physics in college and I began to sort of study it more, I realized that you could basically derive a lot of these seemingly magical equations from first principles and you could work with them in a very logical and reasoned way without having to worry about does this thing side effect or if I call this thing twice, if I apply this function twice and I'm gonna get something different, I was always focused on a problem. So as an example, we're gonna derive this equation. This basically gives the position of an object in a system given its initial position, its initial velocity and acceleration. And so we start off by saying, okay, let's try to get like something, which let's try to get the position first. So we maybe start out with average velocity. Simple enough, that's just changing position over change in time. We do some basic algebraic manipulation and we eventually get there. We have our x isolated on one side, we have our initial position and now we have like this average velocity thing. Well, average velocity is just half of the final velocity plus the initial velocity. And then we say, okay, we don't really know what final velocity is so far, we can't really work with it. So where else can we get final velocity? Well, we do the same thing, acceleration is just changing velocity over change in time. We do some manipulation and for one, we have one of the laws of motion that I gave in earlier slide that we derived from a very simple basic first principle. We also now have a final velocity equation that we can plug right back in. I don't have to worry about, is this valid? Is this okay to do? I sort of just do blind simple manipulation. We plug it in, do some algebraic reasoning and then we eventually say, all right, average velocity is initial velocity plus one half acceleration times time. We plug that back in due to earlier equation. Oh, so that average velocity equation is also one of the laws of motion that I showed earlier. And so, so far, things are coming together nicely. Things are being reasoned about in a simple way. We plug that back into the right side using more of a simplification and we eventually get the equation that we cared about. So something, what I really enjoyed was we would get these equations that seemed sort of complicated or weird or something that looked like they were just pulled out of thin air. But when I actually sat down and took some basic equations like Newton's laws of motion or things like that, I was able to eventually derive it. And so I had this sort of simplified and consistent view of what physics was at least in classical mechanics. And so that was something that I felt was really missing when I went to my CS courses. And so I sort of began, I got to a point around my second year where I seriously considered changing my major to physics because I didn't want to deal with all this weird imperative programming thing where I had to maintain state in my head and do things unrelated to the problem. And so I thought about changing my major to physics and I even thought about minoring in math. About a year later, I ended up not changing my major. I didn't sort of like dealing with it. But about a year later, I started taking more and more CS classes and in 2012 I picked up this programming language called Scala. And I remember one example that I was really fascinated with was the same example that I showed in C++ earlier which was doing an insert into a binary tree. And so that giant code block I showed earlier was just the code to insert into a tree. I didn't even show like the tree definition. Whereas here when I saw it, I have fewer lines and to me a lot more readable code. And there's a lot easier to reason about, right? So when I say what's a tree? A tree is just either a branch that contains some data and then a left and right tree or we have a leaf that just contains nothing. And then when we insert it, we say well if the tree is just a leaf then we just create a branch and have two empty trees. Easy enough. And then depending on what that value is, if the value is less than it, then we just insert it into the left side. If the value is greater, we insert it into the right side. And so there's none of this like weird like state tracking where you have a loop and then depending on some conditions, you might break out of the loop early. And then depending on when you break out your, this value has some specific state that you hope is correct. And so I began seeing a lot more examples similar to this. And I began thinking well, this thing called functional programming seems pretty cool. And so maybe programming isn't as terrible as initially I thought it would be. It would be really awesome if this major I was in, I could really enjoy the theory that I was being taught in class and also actually put that theory to practice and not really hate my life as I was doing it. So the question I began to ask myself like, well, I really, really enjoyed physics and math. I really enjoyed like this algebraic reasoning, being able to derive things from first principles. Can I do the same thing with this thing called functional programming? And so the rest of my talk is going to be basically various examples in functional programming that I've learned over the years that I really enjoyed and that I think sort of follow the same pattern of being able to derive things from first principles, have various seemingly unrelated things come together and be consistent across the various things you're going to deal with. So to start things off, I'm going to give a definition for functional programming because that seems useful. So sort of like the tongue-in-cheek answer you'll often get when you ask what is functional programming is, functional programming is programming with functions. Which may or may not be a terribly useful definition to you. And so we might qualify functions as, we might re-state it as programming with pure functions. And when I say pure functions, I mean functions in a mathematical sense. That is for every valid input, we map that input value to exactly one output type. And so there's sort of two bits of details that is important to note here. One is for every valid input. And when I say valid input, I don't mean just like a subset, like let's say we want to parse a string to an int. I don't mean like for specific strings, the string happens to be integer that's a valid input. I mean, so long as the value that you have is a string that it type checks, then we consider that a valid input. And the second detail is for every valid input, we map it to exactly one output value. And so another thing that comes up is, say a random number generation. When you call a random number generator in the language like say Java or Python multiple times, you're probably gonna get a different answer each time despite the fact that the expression is exactly the same. And so that breaks the definition of function in the sense that for the exact same input, we're not getting one output back. We're getting different output back. So I'll elaborate on that later. But as an example of the sort of first detail, we have a parsing function. And let's say we're gonna take a string and try to parse it and turn it into int. And so our first attempt might just say, give me some string and I'll give you an int. If it's not int, I'm just gonna throw an exception. And that breaks sort of the first detail that I discussed where for every valid input, we're not giving it an output value. We're saying, well, for some inputs, I can give you a valid output, otherwise I'm just gonna throw an exception, which is not really what we want. So instead we can do something, we can change the type signature of the function to sort of be more honest about what we're trying to do. We can say, give me a string and I may or may not be able to parse it into an int. If I am, I'm going to wrap it into some object that is a type option int. If I'm not, if I get a number format exception, the string is malformed or whatever, I'm gonna give you a non-object, which is also a type option int. So we're no longer lying about, our function is very honest about what it's doing. For any string that you give me, I'm gonna give you a valid output value back. I would have to worry about, does this function throw an exception, does this function return null, anything like that. Earlier I talked about random number generation, oftentimes when you call next int, what happens under the covers more or less is you compute the integer from the particular seed that it has, it's going to mutate the seed in place and it just give you the int back. And so if you have various calls to next int scattered through your program, maybe when you do your refactor you say, oh well I have all these exact same function calls, maybe I'm gonna take that expression and then assign it to like val r equals random dot next int and then replace all these calls to r. But now what you've done is you sort of change the behavior of your program and that, now everywhere you're getting the exact same random number, right? The behavior program has changed even though the substitution you've done seems logical to do because you've just evaluated the expression to its value. The more functional way that we do it is, one of the ways we do it is by instead of just returning the int, we're returning the int along with the next int. So when you call next int, it's gonna compute the int, it's gonna compute the next int, but it doesn't mutate the state in place, it'll just return to you the next state with the int together. So if you call next int on the same random number generator multiple times, you just get the exact same value back. So if for whatever reason you have next int scattered through your program, you can just take that factor into its own value and then replace everything and your program is gonna behave the same way. And to actually get a new random number like the next random number that you might actually care about, you have to call next int on the new state that you're giving back. As a sort of a side, I'm not gonna get into it too much since there's limited time, but it might seem tedious to have to continuously get the next state each time you wanna get the next random number. There is a really nice way to do it. The sort of key word that you wanna look for if you're interested in this is a state monad. And you don't have to worry too much about like, oh, I have to deconstruct a tuple each time I call next int just to get the next random value I care about. So this property I've been talking about for the past few slides has a name. It's a relatively fancy sounding name, but it's essentially what allows us to, and it basically describes what I enjoyed about physics and math and what allows us to sort of reason about our programs in a very principled way. And that was referential transparency. And to give a more concrete definition to it, I stole this definition from Rune-Arm Bjarnasen who wrote a book called Functional Programming in Scala that I recommend a lot of people check out. And so we say referential transparency is a property of expressions. And so we say an expression E is referentially transparent if for every single program P, every occurrence of that expression inside that program can be replaced with the result of evaluating that expression without changing the result of evaluating P. So in the case of random number generation, if we just replace random not next int with what you eventually evaluated to and replace all occurrences of it, the behavior of our program changed. In the previous talk, Daniel talked about calling a side-effecting method twice. And so maybe that method, depending on if some global counters is greater than one, then we'll do something and it will decrement a counter. But the next time you call it, I might throw an exception because now the counter is zero. So you've called the same expression twice, but each time you've gotten a different result or different behavior, which seems kind of bizarre when you're dealing with something like physics or math or if you want to reason about your program in an algebraic way. So I have one more math-related example that I thought illustrated referential transparency relatively well. So let's say we have a quadratic equation, just something that comes up in a very basic algebra. And we say, find me all values of X such that this equation holds true. And so you might say, okay, this equation seems kind of weird. Let's simplify it a bit by having some other value equal X squared. And then we substitute that back into the equation without having to worry about is that substitution valid. And then we say, okay, it just begins to resemble something that we've seen, that I've seen before. And so there's a very simple equation, a mechanical process to take a quadratic equation of this form and find all the roots for it. You take the coefficient, you essentially plug it blindly into this formula. So we do some more substitution, do some simplification. And then we say, all right, for that particular equation in isolation without regards like where it came from, we don't even care that it came from like that X to the fourth equation. But we say for this particular equation based on Y, we can say, all right, not Y equals six. Then we recall, we said Y equals X squared earlier. So we substitute that right back in and then we say X equals plus minus root six and we're done. And so we're able to take a seemingly complicated problem, sort of break it down into a smaller problem, take that, plug it into a separate equation, bring it right back and do a substitution again to solve the problem. And this is sort of kind of like simplicity and consistency that I was really enjoying in physics and math and something that I was hoping to find in functional programming. So one example that I ran across recently and ran across a lot before that really irritated me was let's say I have a method that given maybe just for like a web service or something, given a user ID, I'm going to go to like the database or go to some API and get the user data associated with the user ID. And so this returns a Scala future and the way the Scala standard library futures work is upon creation of the future in the background, it's already a running process. So something's already happening by the time you actually get the future. And so at the point where we have fetch data, something in the background is already running. It's already going to the database to get the value it's going across the network to hit the API. And maybe we're writing a retry library which I did a few months ago and ran into this issue. We say, all right, if we get a say 429 which is rate limit back, maybe we wait a few seconds and then we retry the exact same request. And so it seems reasonable to say, okay, if we got a 429 error code, we're just going to fetch the data again. But this doesn't actually do what you want it to do because since fetch data doesn't represent like a value that represents something that has an already running computation in the background, what's going to happen is when you get the, by the time you reach, so this, that little function block isn't going to actually execute until fetch data is finished evaluating. And by the time it's finished evaluating, you're saying, if I got a 429 do fetch data again, but fetch data has already finished executing, so you're just going to get the same value back. And so what you end up having to do to make this kind of stuff work is you have to create a new future. So now you're saying fetch data on 429, call user info again, so you get a brand new future back and therefore you get another already running process back. And so this seems kind of weird that you have to do this instead of just calling fetch data because these two things are exactly the same, yet you can't sort of substitute one for the other because it's going to change behavior program. In one case, you're not, you're just going to get the exact same value back. In another case, you're actually making a new request to the database or to the API service. And so there was a bug I had to deal with at work a while back that was related to this. A nicer way to solve this and a more functional way to solve this is you might, instead of having an already running process, you just have a data type that represents what you would do, just describes what you would do once you run it. But upon creation of this data type, nothing has actually happened at this point. Task is a data type found in Scala Z and essentially you can think of it as a future that has not been run yet. But there's a method call, this isn't actually how it's implemented, but there's, you can think of it as, there's a method call that when you call it, will then actually go and make the request, but until you call it, nothing has actually happened. And so when you call user info and given a user ID, you now have an object that represents, when you run it, I will go to the database to get the data. But until you do, nothing's actually happening. And then you say, well, given this object, when we run it, and if we get a 429 back, then this is the next action I want you to take. And so this transformation is now valid because you're saying this thing, which has not been run yet, when you run it and you get a 429, just run it again. But it's not an already running computation. So you don't have to worry about like, the value in the background has already been like, evaluated in cache and you break like this idea of referential transparency. So that's sort of like the really nice parts about if you work in, if you treat your functions as pure functions, you're able to sort of substitute and do equational reasoning with your programs. Another nice thing is, oftentimes you will be writing lots of different small functions that do one very basic thing, which is what you should be doing. You can sort of like, separation of concerns, you can test them more easily. And so you have all these functions lying around. But if your functions are impure, if they can throw exceptions, if they can return null, you can't really easily compose them because what you end up having to do is, maybe you say a foo might throw an exception or it might return null, bar might handle null input. I don't actually know the type signature that says it takes some b, but I don't know if it takes a subset of bs and bar itself might throw an exception, maybe baz will call into foo or whatever. And so you sort of can't just stare at the type signature and figure out what you want to do. You have to sort of go into the internals of the function and then figure out what it's doing. Whereas if all your functions say for every input, you map it to one and exactly one output, you can sort of compose them all together and expect it to behave in a reasonable way. And so you no longer have to worry about, does this handle null, does that not handle null? You sort of just follow the types and you can reasonably expect to get something that you want back. So another thing that I mentioned earlier was, as part of turning your functions into a pure function, I said don't return null, don't throw an exception if say you were looking a value open to a map and that key doesn't exist. Instead I said we have to use this option data type. And so this option data type is a particular example of what people like to call effects. And when I say effects, I don't necessarily mean like side effects like a print line or like a logging statement. Effects are sort of anything that does something outside of giving you the pure value that you care about. So options sort of captures the effect that this value may or may not be there. We also have error handling where you have like a more involved computation that where a series of errors can occur. And so that sort of captures the effect that is traditionally handled by exception throwing. We have asynchronous computation which we saw rarefied as data earlier in the form of task. And we have input output which is addressed by the IO monad. I'm not gonna get into that but essentially we're gonna have different effects in our programs and we want a nice way of handling those effects without having to sacrifice referential transparency. So the solution is essentially rarefied effects as values that the same solution we've seen in the previous slides. So a missing value I sort of glossed over earlier but we have a missing value can be represented by say an option data type. And the SEAL after class sort of like a detail of Scala you don't really have to worry about it. Basically what it means is you can think about option as a type that you actually care about. Option is a thing that represents a possibly missing value. And then some and none are the constructors for option where an option is either a sum which actually contains the value that you care about and none is just like a sort of set in a value that represents the absence of the value. So when you do like say a look up in a map you say I have a map of food a bar given an arbitrary food. If the return time was bar you'd already know something was off unless there was some like reasonable default bar value. But if the key is missing if we say we didn't check well if there's map contained food if it does that means the particular value you care about is there so you put in a sum otherwise the value is not there we have nothing to return so we just return none. And so when we look at the type signature of this function we say given a map food a bar and an arbitrary food you may or may not be able to give me a bar back. I don't really assuming I'm working in like a functional code base I don't really have to worry about does this thing throw an exception? Does this thing return null? I don't have to do a null check. Similarly with errors we have another we have this data type called either and so you can think about either as it's either a success that contains the actual value that you care about or it's a failure that contains some error value. And so a way you might actually end up using it is you create your own hierarchy of errors that may happen in this particular program. And then for instance to get user info you have a user ID and an access token and maybe the user doesn't exist in a database maybe the access token is expired. One of those errors is gonna happen so you say well I can either give you the user info that you actually care about or I'll give you one of these two errors. And so when you actually call that function you can now say well if I have a success of the user info I'm gonna go do this. If I have a failure of a user design exists I'll go do that. If I have a failure of invalid token I'll go request a new token and retry or something like that. And so you no longer have to again assuming you're working in like a functional environment you don't really have to worry about does it throw an exception? Does it return null? Do I have to check? You sort of just look at the type signatures and then begin like matching things up which is really nice. And so now we've, the really nice part is again types and share of our functions reflect the effects involved. One issue that I might, when I first started learning about verifying effects as data was it might seem strange that okay so when you look up a token for a user ID that token may or may not exist so maybe that particular function says all right I'll give you an option of an encrypted token back. Then you have a pure function that will take an encrypted token and it somehow magically give you like the decrypted token. And so on the client side you say all right give me the token for this particular user ID I now have an option of an encrypted token. But I can't really pass that option of encrypted token into the decrypt function because decrypt wants an encrypted token and I have an option of an encrypted token. And so usually what you would end up doing in a more traditional setting is maybe a token forward return a null or throw an exception and what you end up doing is at the client's at the call site you'll say if I got it if it's not if the null then I have the plain value already so I can decrypt it otherwise if it is null I'll I don't do something else. So it's begin sort of you get the feeling that it might be getting more dirty to work with effects this way because you now have to like deal with like these rapid values and you actually really just want to care about the inner value. And so there's I guess patterns to work with effectful data. And so one of the patterns I'm gonna talk about is called a functor. Ignoring sort of like the strange name essentially the idea that it captures is how can you work with a single effect? So if you sort of replace if you do some substitution in your mind you replace F with like option or list or task or something. What it's claiming is give it say an option of A and a pure function A to B I will give you an option of B. And so a particular instance of a functor might look like this. We say if the option is a sum we get the A value that we care about we apply the function to it and wrap it right back up in a sum. If it's a none then we're just gonna give the none back. And so now we're able to do is the encrypted option and encrypted token you just map over it and the function you pass into map is just going to be the pure function that you care about. And so now you're able to write isolated effectful functions that have the effects in them but also write other pure functions that don't really care where that particular value came from. You don't care that the encrypted token came from like a database or from API or from a file system. You just say give me some encrypted token and I'll decrypt it because I don't really care where it came from. Another interesting thing to note is that we didn't do any null checking or exception handling here. Sort of the option effect the functor instance for the option effect sort of handles it for us, right? Because as you saw in a previous slide if it had a valid value then it was automatically going to apply it for me but if it's a none it was going to thread it right through. And so the call side no longer has to worry about does how do I handle the error case? Well, usually if you have a missing value here and you apply a pure function to it you just want a missing value out on the other side because there's nothing you can do. But you don't want to have to handle it each time you call it. Instead you can just rely on the functor instance to sort of handle that for you. And so you're no longer really worrying about what the effects of this particular effect are. You're sort of more focused on how do I manipulate the data that I actually care about. And so you no longer, again, this sort of goes back to I don't, I'm not worrying about extraneous factors like mutable state or how do I handle errors. I'm sort of just focused on what the problem I'm trying to actually solve is. And so functor captures the idea of manipulating a single effect. There are similar mechanisms for manipulating multiple effects. In the previous talk, if you were there Daniel talked about applicative zip which is essentially how you handle a bunch of independent effects. And then he also mentioned monad or flat map which is sort of how you manipulate dependent effects. If you have like, take the result of this effect and then depending on what that result is do something else. And so there are similar mechanisms but in the interest of time I'm not gonna get into it. All right. We're gonna sort of switch gears a little bit and we're gonna talk about one really cool thing that comes up in functional programming a lot which is called lens. When you have a lot of data in, when you're working with a lot of data in your code base you often want getters and setters, right? So maybe you have like an address data type and the address contains a street and the street contains like a house number. And so you wanna like get the street and then you want to get the house number from the street and similarly for set. Typically these getters and setters are gonna be on a per object basis so it's sort of hard to compose or work with generically. You sort of like give it a particular instance of an object you say get that or set that for this particular object. But we would like to do things in a nicer way. Maybe we wanna compose things together somehow. I'll get into that in a bit. So to sort of see what we can do in that front, let's say instead of putting it on a per object basis we're gonna just reify the idea of getting a setting as data. And so the basic idea of getting a setting is to get something you're just gonna get a field A out of an object S and then to set something you're just gonna change an A on an object S. And so the actual data form of it is relatively simple. Parameterized by two types. S is the particular object type that you care about and A is presumably something inside that object and then you have abstract get and set methods. And from there you can write some interesting stuff. Modify will just simply get it, apply a function that you give it and then reset it so you don't have to do like a get and set on client side. And then the cooler thing is compose which basically says if you have so on the outer layer you have a lens from S and then you sort of like look into the A inside the S and you can get and set. But if you have another lens from A to B so maybe that A has a smaller value B inside it you can take the lens S to A, take the lens A to B and get a lens S to B out that will allow you to automatically jump from the S to the inner B without having to do again like a get and a get and then a set. So lens is composed which are really nice. Composition is really nice. We wanna be able to focus on small things and be able to take those small things and compose them to create larger things. And as a simple example of how this might work say we have an employee that contains a position we have a lens going from employee to position and then maybe we have a team that contains some other stuff among which we have a manager which is an employee and then we have a lens from a team to employee. And if you can take that manager lens compose it with the employee position lens and then now we can give it an arbitrary team we can set the position we can like set the new position of the manager directly without having to doing a get a get and then the set and set. One thing that might be useful for lenses is effectful modification. Again, I'm talking about effects in the sense that we're doing something like possibly failing computation or maybe we can think about the list effect as having a collection of possible values or maybe we go out to a database and look something up and compute a new position based on that. And so what you wanna be able to do is say modify option given a state and given a function that goes from the aid inside that state to some option of A if they don't want an option of S. So maybe for like a modified list given the particular position of this state I'm gonna compute several possible positions and then I want a list of all the states all a list of all the new states that correspond to setting that new A inside that state. And so when you go to implement it you're gonna get a lot of redundant code because all that's gonna happen is you're going to given a state you're gonna get the A out you're gonna apply the function to it now you have an option of A you want to take that inner A and set it on that S so you're gonna say we're gonna map over it take that inner A and call a set. But the code is literally exactly the same for everything the only thing that's differing is option, list, task maybe it's either or maybe it's IO. And this is like really redundant code and just as good programmers we don't we're trying to abstract this out. And so earlier I discussed the idea of manipulating a single effect, right? We had something that just captured idea of mapping over a single effect given a pure function. And so we can actually take that idea of a functor and abstract and write a new function called say modify F that says given a state and any effect for modification I will give you the new state in that effect. And so now when we call modify F we can say F is option in which case we'll get the modify option, F is list in which case we'll get a modify list. And so we've abstracted out all that redundant code into a single method call. So some example function you might run into option either future list IO. And one thing that might come up now is well what if we want to just modify without any effect? Earlier I talked about a modify function that just takes a function from A to A. And so you can think of that particular function as modify it without doing any asynchronous code without worrying about errors maybe it's a total function. We just want and essentially what we want is we want that F of A in modify F to just be a plain A. Now if you sort of like step back a little bit or like screen our eyes a little bit you can if you look at F of A and you say well regardless of what type parameter I feed into F I want a plain A back. You can sort of think of that as a type level identity function. Regardless of what A I give into this F type constructor if you think about the type constructor as a type level function regardless of what A I plug in I just want the A back out. So earlier I don't think I mentioned it directly but earlier we did use the identity function and all identity function does is given any A get an A back out that's sort of like a value level identity function. Now we want a type level identity function which looks pretty much like that. And so let's see what we can do with this. We want to be able to implement modify in terms of modify F and modify F requires that whatever type constructor we give it we have a functor instance. So we say all right let's try and implement functor for identity. Given an ID of A and a function A to B I'm going to get a B out. We see that ID is just a type alias we do some simplification. So now we're given an A and a function A to B I want a B out and that's just simple we just apply the function back I'll apply the function to the A and so now we can take or either modify and implement it in terms of modify F which is good we're beginning to reuse code. Now we might look at modify and say well we can implement set in terms of modify right? We can implement set in terms of modify simply by just ignoring whatever A was used to be there and just always returning the A that was given to us in the call. And so we use the const function which basically looks like that. The first parameter is the thing that's always going to be returned and then the B is you can pass in whatever B you want and it's just going to ignore and keep the exact same thing out. So when you use it in terms of modify it's going to get the old piece of data that old piece of data is just going to be thrown away and then when you apply the function it's just going to give this particular A back. And so this is cool we now have modify and set in terms of this one modify F function but if you look set is defined in terms of modify and modifies in terms of modify F which is implemented in terms of set. And so if you actually go run this code it's just going to be looping forever. So maybe we say all right well set it makes sense to define set in terms of modify in terms of modify F. So let's make modify F abstract then and along the way I also make get abstract. So now I might think so now in order to define a lens we don't implement set and get we have to implement modify F and get but it sort of seems weird to have both of them and so you might think to yourself maybe we can define one of those in terms of the other and simplify how to actually define a lens. So can we define get in terms of modify and what I first thought about it it seems really weird right? Modify is modifying something inside there whereas get is you're getting a value out you're not doing any modification. And so if you just look at the types and this is something that comes up a lot especially when you work in functional programming and when you're working with pure functions as you sort of look at the types and think about what you want. So modify F gives us an FFS back but we actually want an A value. So it seems we're kind of we're out of luck here we can't really get an A out of an FFS nowhere in FFS do we have an A. If you step back a little bit we say well we need some way of ignoring the S parameter to F and we get an A back right? So we're now again thinking about F not as a type alias but maybe as like a type level function. So regardless of what S I put in or regardless of yeah what S I put in I always want a particular A back which sounds really familiar to something we saw in the previous slides which was a constant function right? Constant says give me some A and I'm gonna give you back a function from B to A and regardless of what B you give me I'm going to give you an A back. So what is the type level function it looks like? Two type parameters is Z or Z which is the thing that you actually care about and then A which is the thing that's gonna just be ignored and so when we define a function instance for to make modify F happy we're gonna fix Z to be a particular value and then we're gonna leave the A parameter free because a function wants to type a type constructor and so all right now we're safe to implement it the map call we have a const to Z A we have a function A to B we want to const Z B back we do some simplification we have a Z a function from A to B and we want a Z back the only way we're gonna get a Z so just another we're going back to in a pure functional setting and where we don't have like nulls or exceptions or anything like that in this particular case there's really only one thing you can do which is just completely ignore the function and just return to Z back so another thing that programming in a functional style gives you is ability to sort of like guide you through how you want to implement the code and if you want to look up this technique the key word that you're looking for is called parametricity I think there's a talk later today by Chris Nutty Com that's gonna talk more in depth about it so we have our functor for our const and so now we call modify F with that const and so it might be sort of weird to follow it but essentially what's happening is you're going to the call to modify F you're going to say given the currents A inside it I'm just going to give the A right back because const Z of whatever is just it's just Z itself so that's valid and then when you go to apply when you go to map over this const to sort of set that state set that new value inside the state I'm just gonna ignore the thing completely and so while on the other side you're gonna get a const Z of S back we know that under the covers it's just a regular Z and so we now have essentially what it's doing is it's storing the Z value inside something someone's gonna try to map over it but we're just gonna throw that function away and then we're gonna give that stored value back and we're able to get the Z right back out and so what we've now done is we've implemented get and set in terms of modify F modify is also defined in terms of modify F and so it's sort of interesting to see that the idea of a lens which is getting and setting on objects is now fully defined by an effectful modification on that object and so the point that I'm the interesting point that I'm trying to get at is well we were able, it's cool to see this it's sort of like a neat thing that happens to work out but we had this sort of like idea and const thing that we were using to implement get and set in terms of modify F and it might be easy to think like well maybe it just conveniently happens to work out in our favor in the context of lenses right ID just happened to be what we needed to make a non-effectful modification and the const just happened to be what we needed in order to get something based on a modification so I'm gonna show another example of where ID and const become really useful and just to show that they're not just like a one-off trick that we use and so the example I'm gonna talk about very briefly is called traverse traverse is a really cool thing encourage everyone to check it out but I'm gonna sort of like hand-wave about it traverse has sort of like a complicated type signature if you recall, if you're in Daniel's talk you can sort of just ignore the applicative for now just sort of gloss over it but essentially applicative allows us to take two G of A's and then like get one G of A back by sort of combining those two based on some sort of function and so what traverse says is give me some F of A you can think of F as like say a list give me some list of A and the function from A to some effectful B I'm going to, you can think of it as apply this function to every single A so we now have like a bunch of different effects and then we're gonna combine all those effects we're gonna collapse all those effects down back into the original F you gave me and so if you sort of instantiate F and G it might become more clear so if we instantiate F to be a list and then G to be say an option you can think about traverse as doing validation you have a list of maybe unvalidated you have a validation function that goes from A to option of B and the other side you're gonna get an option and list of B out and if the result of applying this function to all the A's was some in all cases you're just gonna get a sum of the list of validated values back out otherwise if you hit a none at any point you're just gonna get a none back another way you can think about it is fix F to be list fix G to be task the async effect that we talked about earlier and what this is doing is essentially given a list of data take each piece of data fork it off into a new its own computation and then take all these new async computations and join it into a list so it's for like the scatter gather idea so traverse traverse this type signature again in a more general form in a in a curried form looks like that given an F of A given some effect full function on A we're gonna get an effect full collection or context back so earlier I talked about we're going to see this identity and const thing again so what happens if we fix G to be identity let's replace any where we see G with ID so we have F of A to A of ID of B to ID of F of B remember that ID is like a type level constant function so we can sort of ignore that outer type instructor we do some substitution and we see it goes from F of A to A of B to F of B which should look pretty familiar at this point we've seen this in earlier slides twice now this is exactly the type signature for map on Functor Functor says give me some effect a pure function I will give you I will apply that function to the value inside the effect and you're good to go traverse with identity is exactly that so we're now seeing two for one we're seeing identity is not just a cute trick used for lenses it's useful in other contexts as well another thing is this idea of traversing doing like a factful traverse over like a collection is also related to just manipulating a single effect we're going to do a similar thing for const the const is a bit trickier for traverse we have to assume that there's some way and we'll see in a bit why this is a reason but we have to assume that there's some way to take for the Z type parameter we have to assume that there's a way to take two Zs and combine them into a single Z the actual keyword that we're looking for here is called monoid I'm not going to get into that too much but essentially you can just think assume that somewhere we have a reasonable binary operation on Z that would take two Zs and produce two SZ we do some substitution so we say give me an F of A a function from A to const Z of B and I'll give you back a const Z to F of B back we do some substitution and we say given an F of A and a function from A to Z I'm going to give you a single Z back and what this means is remember we have this ability to take any arbitrary Z and join them together so what this actually does under the covers if you say make F a list and Z an integer or something it's going to take that list of data it's going to take that list of data and it's going to map all of this bits of data into say an integer it's going to take now this list of integers and use like addition to reduce it all down to one value and so again we have this reverse function which seems to be doing an effectful traversal over some sort of data type and it's capturing both the idea of manipulating a single independent effect the function which we talked about but also it's capable of reducing a collection of values down into a single value and so all these seemingly unrelated things are sort of coming together in a nice way and this is sort of the things that I really that I find really fascinating that I really enjoy and there's several other examples of this but in the interest of time I'm not going to get into that but lenses and traverses are sort of like the two big things I discovered over the past few years that I really really enjoyed and if you're interested in learning more I have a list of like so for one there's a book by Rudolf Jarnsen and Paul Chuzano called Functional Programming and Scala that I really recommend people check out in terms of libraries there's a list of libraries if you're doing Scala development already that I would encourage people to check out if you want to program in a more functional style so cats and Scala Zd are two general purpose functional programming libraries that will give you general tools like Functor, Applicative, Monad, Identity, Const and then there's some other libraries like Arcannot which is for purely functional JSON encoding and decoding, Adolf which is purely functional parsing, Monocle which sort of takes the idea of lens that I just talked about previously and takes it to like a whole another level of abstraction which is really awesome and a shape list which allows us to do like really serious and magical abstraction like it's able to abstract of arity of functions and it does a lot of crazy type level stuff. I mentioned the word monoid earlier and there's a whole group of so monoid comes from this mathematical branch of group, abstract algebra or group theory and it comes up a lot surprisingly a lot in like data analytics and things like that where you're like working with data a lot. Algebra has some stuff, it's from Twitter they use a lot in their Hadoop MapReduce engine. Algebra is a joint effort between Twitter and Eric Osheim who is the author of Spire to sort of share, have a common foundation for the Algebra library and the Spire library and then Breeze is a similar library out of UC Berkeley. If you're working in like the big data space I guess and you want to look more into functional programming there's Skulding which is from Twitter which is a wrapper at MapReduce but allows you to work with MapReduce in a more functional way. Scooby which is out of Nikta, similar to Skulding and then there's Spark which is separate from MapReduce but the interface is sort of the same. You work with your data in a functional way and at behind the scenes it's sort of like handling the effect of distribution and reading and writing for you. And then if you're doing systems programming which is what I do at Box Often something I'm really excited about is that we're seeing a lot of these like purely functional systems-y libraries coming out that we're now able to write like a purely functional like backend system where you don't really have to like say oh well I'm writing into a database so I have to sort of side effect in this particular isolated corner or I'm like doing remote calls so maybe I have to use like I have to side effect to send something over to network. There are libraries out there to help you do this in a purely functional way and so Doobie is I think there's a talk by Rob Norris later today that's purely functional database access backed by JDBC. HTTP 4S is purely functional HTTP client and server. Remotely is purely functional RPC that's out of Verizon and then there's also scholars that stream which is purely functional streaming IO. And so there was, I forget the name of the talk but someone had did a talk a while back I think in Australia where you sort of took Doobie, HTTP 4S and scholars that stream and combine them all together where you had like requests coming in as a scholars that stream into a web server backed by HTTP 4S which then made purely functional database call via Doobie and then propagated that back up. So the entire like HTTP thing was like just one stream you have streams in, you have streams out and it was really nice to work with. And there's tons of other libraries out there these are just some of the ones that I use or play with often. But other than that, I guess that's all I have for today.