 Good morning everybody that was more enthusiastic. I thought I thought everybody but me went out to drink last night All right, and welcome to my keynote ruby versus the Titans of FP I'm gonna talk a little bit about myself So that you know where I'm coming from with this because it's gonna be more of a story So I've been a hobbyist programmer for about a decade the very first thing that ever programmed I was 12 years old Who here remembers Q basic on like MS-DOS? Who here remembers gorillas? My very first line of code was to cheat in that game I made my brother always play player two and I made his win values display something other than what they are Just a little bit to the left or right so that he can never hit me and that Began a lifelong love of programming I'm also fascinated with functional programming. It's a very mathematical discipline and it's it's very easy for me to reason about what I'm doing However, I'm relatively new to industry I'm at my first job at maybe link a little company. You've probably heard of from the three other speakers I've been wandering around here and I've been there for eight months and it's my first real experience with ruby and So while I've I've experienced Haskell enclosure and JavaScript It's only really this year that I got in a ruby yet somehow I snuck on to the stage of Ruby Conf is a keynote speaker I'm still trying to figure that one out All right so when I first started learning Ruby my Motivation was like oh, hey like I need to do this for my job, but I also wanted to drag all my functional knowledge with me and Not many people use a ruby in a functional matter if you want to Create something you you have an object for it and it has methods and everything's oh, and it was like, okay I'll roll with it until a few months ago When somebody poked me to do a CFP and I finally decided to actually explore and I was like, okay I'm gonna make functional programming work in ruby and this talk is a documentation of My past three months distilled so that you don't have to see me yelling out a rebel trying to figure out what's broken Right so Welcome to ruby versus the Titans of FP Before we get started we want to talk about what functional programming is because not everybody's familiar with it Now if you ask 20 people, they'll give you 20 different definitions Some will people the math some will people some people will bring out their Bible of category theory and sit you down for a Three-hour lecture. I like to be a little bit more pragmatic So to me I like to describe it as this It's a programming paradigm that focuses on functions as transformations over generic objects and data structures as opposed to objects that we model a Good example of this is a login object now if somebody I think everybody here has written a login object if they've worked on some web app and Usually when you approach it you're like, okay I'm going to give it some attributes and it's going to know its internal state But then it's also going to know how to validate itself. It's also going to know how to delete itself So it's going to save itself to the database Functional programming separates those two things so you can still have a login object Which can end up being a generic data structure. It's like, okay. I know the user I'm associated with I know if I've been deleted that but then you'll have a separate set of functions that can operate on that object for example To invalidate it. So why is that a good thing? Well, one is easier to reuse logic and I think this is one of the biggest benefits for it I'm pretty sure everybody's ran into the situation where they're like, oh, hey, this class has an amazing method that I really want to grab and But I can't subclass it for whatever reason because inheritance just scares me sometimes And so it's really nice to have that already separated so that you can then figure out how to make it generic for an entire class of objects Unless you compose smaller units of logic together, which will be an entire 10 minutes and just presentation And it can keyword can and giant air quotes result in cleaner and more performer code It's done the right way If it's done the wrong way It can get kind of scary right So these are my five key features of Functional programming language and this is probably contentious if you go to like the functional programming lexicon There's like 300 definitions inside of it. But these are the five things that are important to me Higher-order functions carrying composition functional purity and immutability. We are only going to talk about three of those today Functional purity and immutability are things that we can do through the data structures that we use and through how we treat the flow of our program However, higher-order functions composition and carrying tend to be things that are more primitive in our languages And if we don't have support for them, we end up losing a lot of things So today I'm going to compare Ruby versus closure Haskell and JavaScript in order to see if we have those things that make other functional programming languages nice And we're going to start with a little thing called closure Now closure was born in 2007 And it is of the list family and that makes some people very happy and that makes some people very sad So what makes it a functional language it has higher-order functions It has first-class functions, which just means that we can take a function and stuff it into a variable and then use it Anywhere we want and then its standard library has immutable data structures And this makes me so happy and I wish I had more chance to see is it? This is an example of what a function called enclosure looks like It's just a list The first thing at in the list is a function everything else is arguments that list is actually short for list processing and This seems elegant and simple and nice But then you end up with programs that look like this This is a lazy take and those programs at the very bottom of the slide either make you make a face like that cat Are you put on a robe and you become one of the old wizards of lists? All right, but we're not going to dive into anything crazy with closure. We're going to talk specifically about map Going back to our definition Map is a function that takes arguments What are those arguments? Well very first thing is a function that we want to transform some collection the examples that we're going to use and that you're Going to be sick of it at the end of 35 minutes is going to be increment We're going to increment and decrement so many numbers. It's going to be great And then the second thing that we pass in is a collection which is going to be a standard array for our purpose and So this is what it ends up looking like We we map our increment function over one through five it returns two through six and we've already arrived at the first capability Which is higher-order functions a Higher-order function is a function that either takes in other functions as part of its arguments Or returns a function as this result The example being our map taking in a function for his transformer Can we use this in Ruby? Obviously I'm pretty sure everybody's just like why Everybody knows we can do this so The standard way of doing a map in Ruby is to have some collection call map on it as method and then pass in arguments We're going to create something a little bit more generic for reasons that will slowly become clear as we walk through this So we're going to start with an uprock and give it our two arguments Function as our first argument which makes this map a higher-order function and then our collection and then we're going to cheat and We're going to use we're just going to call the collections map method If it quacks like a duck it must work for us And then this is if you've ever read the closure documentation f and coal are used all over the place And this is what they actually stand for a function collection Congratulations, you can now read 90% of the closure documentation because that's all it is It's all it's all signatures All right, so how do we use this? Well here, we're going to create an increment that just takes in a number and returns one to us We are going to Give ourselves a list of numbers two through four and then we are going to use map call In order to invoke it with our arguments This drives me insane Fortunately Ruby is nice to us and we can hide it This was a mind-blow like two months ago when I was like learning and I was like, okay I'm going to get tired of using call anywhere odor syntactic sugar for it. It's good This is at the interpreter level So if you define an object that has a call method on it It has this alias on it as well. And so you can hide all your calls It looks kind of beautiful the dots still throw me off because I want them to look like message calls But it works out a more complex example going back to the logins that I keep talking about is like, okay We're going to create an anonymous proc that not really anonymous. We're stuffing it with something We're going to create a product that takes a log in and sets to delete it at the time now And we're going to say okay is deleted at not nil cool. We deleted something and Then we're going to create a list of logins or a set of logins or a vector of logins so I have not found a use for vector in actual production code yet and We're going to map over that with our invalidate log in helper and so we've met our first requirement here that we can use higher order functions and The syntax is a little bit different than what I'm used to but it's there And so the next thing we're going to cover is currying and we're going to turn to our old friend slash enemy Haskell Haskell is From was created in 1990. So it is one year younger than me and I officially feel old now and It's from a family of languages Called ML which is short for meta language, which I always thought was machine language until like two days ago And somebody corrected me on this and the things that make it a functional language Is that everything is curried inside of it? Everything is pure and it has the most beautiful type system that I have ever seen in the language Although it also drives some people insane So what does the function call look like in Haskell? Well here we're going to create our increment function by calling add which is just going to be a plus sign here With one and then we're going to take that increment and then pass it into map With two three four and we get three four five as we expect But what was with that ink? Add takes two numbers and we only give it one and it didn't blow up and give us our argument error. This is strange Let's investigate In the worst possible way So We're going to talk a little bit we're going to diverge a little bit and talk about him leave owner type systems Which might be a little bit heavy-handed, but will help us figure out what's going on here so We can be here talking about them forever, but two things that we need to know are are There is that it can be used to express the signature of a function and that Haskell uses it to annotate types And it will check against the types that you annotate An example add or at least add is we're used to we have a function name here And then we take two arguments here, and we just group them in prevents to say that we're taking them at the same time We have a function arrow, which tells us we're going from something to something and it gives us a result Congratulations. You all can now read type signatures in Haskell For the most part All right, so this is how we're used to doing it. We call add with two numbers. It gives us one number it yells at us if we give it He yells as we give it one number and blows up and we get all sorts of weird things And then we get a 30 mile long stack trace, and it's never fine Haskell does things a different way so Haskell Still has an add function, and it still has the same behavior where it takes in two numbers and it gives us back a number But we can only give it one argument at a time And when we give it an argument It will return to us a function Waiting for the rest of its arguments And so let's go back to our ink and figure out what happened So we have add here, and we give it one And so we pass one in here, and you can guess what we got back a Function waiting for the second number And this Gets us to our definition for a curried function and This is why you do not rewrite slides at 10 o'clock at night before you present This slide right here. I rewrote this three four times hated definition, and I just said okay. It's midnight I'm not gonna mess with this anymore So a curried function is a function that upon being applied to Less than the total set of arguments as opposed to takes returns another function waiting for the rest of its arguments So our add function takes two things We give it one it returns a function waiting for one if we had a reduce that took three things And we gave it two things it would return as a function waiting for the last thing so and so forth if we had ten And we gave it five we gave it would wait for five more and just give us a function waiting for that And let's us do some borderline dangerous things so we're gonna implement this in Ruby and Where you're going to use our best friend closures in order to do it So here we're going to create an ad and we're going to have a proc that takes an x and When we call this with a number it's going to return to us a proc that waits for why When we call this then it will give us results So we're going to go create our friendly increment function By just saying add one and it's going to bind that one to x and we're going to get a function that waits for Why and we'll just add one to whatever y is So we can call it immediately and we get ink to and we expect three or We can map it and we get our increment array as we've gotten the entire time. I hope This is the easy slide so there is a better way nobody wants to write 20 nested closures luckily We have native currying this made me jealous because I came from JavaScript And we don't have native currying in JavaScript So when I saw this I was really happy because then we can end up writing our functions like we normally do XYZ Do a thing have it automatically currying handle for us and in addition to doing all the things that we can do with currying We can also just call it at any time with all of his arguments And then we just get the result back immediately so a quick divergence in the order of arguments you'll notice that Haskell Closure and our Ruby map all had the same order of arguments and this is why if We wanted to create a function called ink map that Increment that iterates over a list of numbers and increments all of them We can build it this way assuming that our add and map are curried What if we wanted to decrement everything instead? Well, that's easy enough to do We use our ad and just give it negative one instead of one and build up to function the exact same way and through currying we can build entire families of functions of Affirmatives I I could write a mathematical proof right now, but it would not be good. I can create every step function From my ad I can create all every iterative transform function from my map and That makes it easier for us because then we don't have to worry about those things And we get to abstract a layer away So we've got higher order functions And we've got currying What's left our best friend? JavaScript so JavaScript is relatively new 1995 and It doesn't really get to be put in a family. It's kind of like scheme C syntax and so it's not really like anything else. And so we get to name it its own thing What makes it a functional language? Well first-class functions which we have determined lets us do higher order functions and closures Which let us do currying But pass that it doesn't really have much it has really strong functional programming libraries But not many things built into language And so despite the fact that we have all of these really low-level tools in JavaScript The core API doesn't really like Us doing things in an fps on some places example Array So we created array three numbers Map is a method on array. And so if we want to access map, that's how we have to get it pop Gets a little get something off of the end of the array and gives it back to us and it mutates the array underneath Which destroys? Mutability and doesn't really work out for us in a functional flow Wait a second doesn't Ruby do these same things? Hmm It does exactly the same things actually Map is also a method and pop also mutates and so a lot of the stuff in the standard library That would create friction for a functional programming flow Exists in both languages So that gives us a clue because we can look at how functional programmers in JavaScript solve their problems In order to figure out how in Ruby I can solve my problems and the answer is Functional programming libraries in the beginning there was underscore It was okay Kind of but it got the order of arguments wrong And so low-dash came around But unless you lose low-dash a fee nothing was carried so random to came by and Everything's curried and everything's in the right order of arguments and everything has the Haskell names for its functions and It lets you pretend that you're not in a browser And so it ends up being my favorite thing Out of all the things in Ramda My favorite thing is compose Because this lets me glue things together How many people have ever done this? It's you write a method it takes in a thing You invoke it and you save off the result to something and then you take that result And you immediately pass it into another function, and then you save up off that result, and then you go Pass save pass save pass save pass save until 30 years later You're finally able to return the thing from all these functions that you've been running There is a better way in this case Ramda gives us a nice compose Ramda also gives us all these nice courage functions And so I'm going to define add to here as oh, hey, I'm going to create an incremental with add one Glue those two functions together and then the Argument die passing gets passed into one of the incrementers the output of that gets passed into the next incrementer And so we create a chain or a pipe of functions here And so our add to two returns four This is a little bit more complex, and if you get the type signatures Make you feel weird ignore them. They're not there They're slightly grayed out for a reason Here we're going to create something a bit more complex map reduces so if you wanted to do a map reduce usually you have Some function that takes in something call this map saves off the result calls reduced and then passes that back Here map reduce are Curried because they're in Ramda standard library map takes in an incrementer Well a transformer and a collection we go to a transformer. It really gives us a function that waits for a collection reduced takes in a Reducer an initial value and a collection and it returns a final value and Because the types match up for all that stuff we get to just glue them together like this This also lets us be point-free so that we never have to mention our data And if we never mention our data, I can't miss type which is why I love it So benefits we get actual easy logic reuse if We create an increment function and a document function. We can glue them Exactly two ways together But if we had 20 things Then we could put those together like Legos any way that we want And so we get actual reuse of logic and we can do very strange things with it we can also compose our compositions and This makes for really easy refactors a really good example is a response for request response cycle I have a composition that takes a request into some internal state I Have a composition that does something with their internal state And then I have a composition that takes the internal state and maps it to the response object I can isolate those three separate things and then compose them together and Make my entire request response cycle into a single function Which ends up being really clean when you have 300 routes So how are we going to do this in Ruby like all things? Here we're going to create a binary compose that just worries about two functions We're going to create a outer proc that takes in Two functions and it's going to return a proc that waits for the arguments Once we get the arguments We're just going to call Why With the arguments and the output of that is immediately going to be passed into x The reason that this goes wide x instead of x y is because it works like mathematical composition There is there's usually a pipe Function that does the opposite order in most functional libraries And so we're going to create our ink here and we're going to compose it just like we did in the JavaScript example and We if we add two to four we get six back in the same world If we want to do this some more than two functions then We can take the compose that we just made made and create a very out of compose and Here we're just going to say oh, hey, we're going to take in all of our functions and Then we are going to reduce over that with our binary compose operator and That will do the exact same thing only with as many functions as you like so here we can Create an add three from three increments why we wouldn't just use add three to create our add three It works out for this and then if we add three to four We get seven back Nobody wants to write this this is one of those snippets of code that you'll find yourself using everywhere once you're used to it And so the next question is what if I just want a gem? I wrote it and so if you go to Ruby jumps and you look up reductio. It only has three functions add compose and map because over the three functions I need for this demonstration and It works the the add is carried as you can see and The compose is very attic so you can use it to glue 20 functions together. Is that a good idea? Never. Can you do it? Yes, I have it's not pretty Don't don't ever look at my github. It's a scary place all right and So this is Is something that I'm very happy about because I got comfortable enough in Ruby To create a functional library and so what have we established Ruby can do Well, we set out to find higher order functions composition and carrying comparing it to three different languages And we found all those things We haven't looked at functional purity. We haven't looked at immutability, but the tools that we have are enough and so While people like to pit Ruby against other functional programming languages Nothing stops it from being part of a circle, too. And that's what I've got for you today. Oh I went through that way faster than I expected which means I have question time So this is gonna be interesting. So next steps if you want to learn more about functional programming Dr. Frisbee's mostly adequate guide to functional programming is a book on github. It is written by a cute badger That is actually Brian Lawndorf who is a functional program guru at Netflix all the examples are in JavaScript, but it should be easy enough We also have my repo for reductio, which is also a gem now I want to get more discussion going because I feel like I've trapped myself in this bubble trying to Divine things the hard way in order to try and learn things, but now I want to talk with people about it So if you're on Twitter tweet questions at me or just ask me them in the next 10 minutes and then Tweet with the hashtag functional Ruby and I'll be looking at it I hope other people will be looking at so we can we can start a discussion and then please help me I have never written an open source gem before and Yard is confusing Oh Tara has convinced me that I need documentation so if you're a functional programmer and you would like to help with that or if you're not a functional programmer and you Want to learn please? Please go help you with this And before I'm done. That's my contact information on the left. I want to give a shout out to Transcored first. I want to give a shout out to RubyConf because it has been a hard week for me as a trans woman of color and I have felt very welcome here and I am very glad it's my first RubyConf too. So I'm happy that I made it out here But if you know any trans people were Alex I looking for a sense of community the link up top is a link to Transcored which is a global support group that would love to have more members and if People have not already sold you going to Kool-Aid that is maybe link yet Then we have this nice Engineering blog link here that covers a bit of our culture and so I think we are good for questions. I was not prepared for this Yes Okay, so the question was that they have trouble seeing the benefits of point-free style and It's it kind of seems Obtuse and not indirect because you never mentioned your data. So you're never sure where your data really is and so one of the things that really appeals to me about point-free style is that we get to Walk away from the constraints of our data With the map reduce that I demonstrate earlier It doesn't matter if it's an array or if it's a linked list or If it's a maybe or either or an IO or some other some other funk door I Don't worry about that. I just know that there is an interface that anything coming into this function Has to deal with and then that lets me use it generically and so that ends up being That ends up being part of the benefits for me because I can just say in my type annotations like oh this takes in a monad and It returns blah, and then I don't really have to worry about my data pass that Does that answer your question? Yeah, so It's kind of like duck typing. Yeah, so in in in JavaScript. It's actually Treated that way. So if you use Ramda and you pass in something that has a map method on It as the mappable to map it will use that method on it And so you get something akin to that Okay, so the question was And please correct me if I just completely fudges is that eventually you have IO eventually there has to be some side effect All programs have side effect. Otherwise, what are they really doing? right and So how do you handle that in functional program? How do you? Deal with that when you have basically two styles where you have an object Defined a OO style that has to do these things, but you also want to create this logic and a functional style and If you went to the composition talk James actually had a really good thing about this So go back and watch his talk, but I'm going to try on precious Well, my first instinct is to just tell you use a IO monad, but that doesn't exist in Ruby yet I'm working on it so That's that's one of the things where Right now in our company I'm on a team that's using a react and so the way that I handle it is that when I do compositions I push that to the very end of our chains and so you can because Composes because compositions are functions themselves and you can compose them with other things I can create a pure composition that goes from point a to b and then in my actual app Just compose that with something that takes in data and causes a side effect And so you get a you can you get to create a very clear Divide there and say like oh, hey, this is my pure code inside of this library Everything is beautiful and then the side effects get pushed to the edge of your app and that's how I tend to handle that I have strong opinions about active record scopes Okay So I Wasn't able to hear the second part after scopes Okay, um the question was how do I feel about active record scopes ignoring the rest of the library? Um, I like that Scopes are just kind of composing on each other in order to build up a sequel query I don't like that at any point somebody can cause a side effect by doing something that actually loads from database database Calls are one of those things where it's like. Oh, hey, I knew I Loaded up a user and I automatically went to the database and I'm like, yeah Can I separate that stuff somehow and so When I write scopes, I try to write them to say what I would write compositions where I try and Push anything that would possibly load as far down the chain as possible Instead of being like, oh, hey, like I need to load the association for this thing and then a database hit occurs because of that So that answer your question cool. I feel like I'm back in class. I should be standing behind the podium, right? Anybody else I have not okay, so the question was have I done benchmarking because They have heard that currying might propose Mike what are words words are hard it might impose a performance penalty and so I have not done that benchmarking I want to do that benchmarking when I Start fleshing out reductio just so that we can say, oh, hey, like this is a performance penalty You can do three less operations a second, but it gets you such beauty And so that it as a thing that I also want to work on I have not heard of it But I have also only been a rubius for eight months. So my opinion might not be always qualified All right So answer your question Okay, that's good. So let's see if I can go back to So the question was why do we not want to compose 20 things together, why do we want to keep our composition short? well, and this is Act this is actually a really good demonstrator. So looking at the types include for this. This is already Kind of complex. This is doing a lot of things. It's iterating over a list is applying a function to everything to that list We get a new copy of the list back with all those things transform and then we start folding over that list in order to get a final value this encompasses a lot and if we Were to start adding new things on there like we want to map and do x thing We want to map and do y thing we want to map and do z thing Then it's really easy to just look at a page of a composition and be like, what does this even do? I do this all the time and That ends up being a problem because I'll go back to old code for example something I did for hackathon I was like, oh, hey, I could bang this out in five minutes because it's just one giant composition But then when I go back and look at it later. It's like What was I doing? it helps that there is a vocabulary When you use a standard functional libraries, you'd be like, okay This thing is head so it grabbed the first thing off of this array and then this incremented it and then Disappended it to something else But it's still it still gets to be difficult once you get past a certain length and because Compositions can be themselves be made of compositions. It's very easy to say, okay, I have 20 things here Let me grab these five put them in their own composition and then replace those five with one line referencing that composition So it also gives you easy refactoring Which ends up being a beautiful thing because then you can have your short like three five line things But then still encapsulate all of your functionality into one single function that gets passed and has a call back to something Does that answer your question? Okay, I've got four minutes left Anybody else Last call cool. Thank you