 Look at that full stack fest. There's my old cat, Zach. OK, so we got a lot of code to write. Right before lunch, Peter gave that great, really great talk on some functional stuff in Ruby. And one of the things that he mentioned was that that wasn't just crazy stuff he'd done on the weekend, but stuff he's actually been using. Well, we're going to follow his talk after lunch with crazy stuff I did on the weekend that you shouldn't use. But so basically, we're just going to play around, look at some stuff, how lambdas work. We're going to actually build lists. A lot of times you hear about lambda calculus and all of the crazy stuff. So what we're going to do is we're just going to build up list implementation. We're going to code it. It's going to be fun. And then you'll get back to talks that are useful. So a couple of things just to start off. Let me get my reading glasses. I'm getting old. I have a script, so. OK, so we want to start off. But if you haven't seen lambdas in Ruby, lambdas work pretty simply. They start with the little pointy operator. They take an argument and you can return something. So this is basically return it. And you can execute them pretty normally. So if you want to do it like that, I have a little mapping here. So as we go through, oh no. Ah. Oh, that's why. There we go. So you can see as we run, it prints a 1 down there. You can also, which is what we're going to be using a lot more, you can do this really odd syntax where you use brackets to call it. It's just a nicer syntax, I think, for stuff. So it actually calls it and gives you a 1 and a 2. OK, now, of course, return it doesn't make that much sense as a name. And since it returns whatever you pass into it, the real name for this is identity. So we've got what we call our identity function, which returns whatever you pass into it. Now, I'm going to be using it a lot, so I'm lazy and I don't type that well. So we're going to just call it I. So whenever we use I, it's a function that takes an argument, returns itself. Now, having a single argument isn't always that useful, unlike everything else we're going to do. So what we kind of want to have is if you have two args, how do you implement that? Well, we only get to have one argument in our lambda. So if we want to do this, we actually just return another lambda. So basically, we're returning a function. We're calling a function with x. We're returning a function that takes y. And in this case, we're just going to return x. Now, an interesting thing about this is if you think about it, this is a function that I give it, and it returns me a function, and no matter what I pass here, I get the first argument back. So this is really kind of constant. So in this case, if I call constant and put hello, goodbye, so see, I've kind of got the two arguments here, then I always am going to get hello. So no matter what I pass here, I get hello. Seem reasonable? OK, so constant, of course, is a really large word to write. So we're just going to call it k. And I'm going to actually clean it up a little bit. So the way we're going to look at lambdas in this is if you have more than one argument, it basically just looks like this. You have your first lambda, then it returns a second lambda. If you have a third argument, it puts it there. OK, so that's basically lambdas. Works out wonderfully. So what we want to do, though, is we want to go through the exercise of building lists, with this being all that we have. Now, as any good, happy developer does, we always write our code with tests. So basically, we would want to do something like assert. And a very simple test, a very simple test when working with lists, is whether or not something is an empty list. And we would expect that if I had something called empty list and I called a function called isEmptyList, it should be an empty list. And our assert should pass. Notice I'm using the bracket way of calling things. So if we run this, of course, it sure would be nice if we already had everything, but we don't. All we have is I and K, I being the identity and K being the constant function. So we get an error on initialized constant assert. So I'm going to copy this out because this is kind of our larger we're done when we have that. So let's look at what assert is. Well, if you've ever used assert, how many people use Minitest? Here, awesome. How many people use RSpec? So for the RSpec people, I'm going to talk a little slowly around this. This coming from somebody whose first Ruby code that I ever wrote was actually RSpec. I love RSpec. I use that as my day-to-day tool. But assert is sort of the core of everything. So assert basically takes an argument if it is right or true, we print T. It takes an argument. And if it is wrong or false, we print an F. And that's what assert does. It's a very simple function. Most people use it. Even the RSpec people, it's kind of like expect. I won't make any more RSpec jokes because I do use that as my day-to-day one. I love RSpec. So if we want to write it. So basically what we end up with is we want to be able to say assert true. And that should print a T. And assert false, well, that should print an F. So if we run this, though, what do we get? Well, we still haven't defined assert. But we've got two tests, effectively. They're visual tests that say what assert should do. Well, it's got to be a function. So look at this, underscore. If I don't care what the parameter is, which I don't right now, I'm just going to use an underscore, which sort of just takes it out of vision. So if I just return true with assert, well, I don't have a true, so that doesn't work. So let me make a true. I don't know what it is. It doesn't matter, so I'm just going to make it an identity. OK, now I don't have false. I don't know what that is, so I'm just going to make it the identity. Now, I don't get any output. That goes against what my things are. So let's just make this print. I'm going to use p, a t. Now you notice I'm actually printing a t twice. Ooh, it puts that thing there. Let's use a puts, so we don't get the quotes. So now you can see I got t's, which, ideally, that's what we want everything to do, except that here we said if it's false, we want it to print an F. And that's not the expected behavior. So even though the assert is working, well, that means that this hard-coded thing is not really what we want to do. So instead, let's actually define it here. So our true and false are what's bound there. Well, the assert is just going to take something in. We'll make up a word, boolean. And we'll just execute it. Remember, you can execute with a dot and the parentheses. So if we do this, now we get a t and an F. That's what we were expecting. So we've got basically assert working now. That makes me happy. So now we can come back here, taking baby steps, because of course we do TDD, uninitialized constant empty list. Well, what do I want to have happen? Well, I guess I could just make this true. Well, assert's going to call it. So let's see what happens if I just make it true. Ah, uninitialized constant empty list. Well, that makes sense, because I haven't defined that yet. So let's define that. I don't know what it is, so I always use identity as my default. Oh, no. When we get that error, it means we don't have a function. We forgot that we're only really dealing with lambdas here. So at this point, assert is empty list. Empty list returns a true, and we're done. Here's a picture of my other cat squeaks. OK, let's get on, because of course, that's not really what we want to do. That's not totally enough. Well, what if we give it something that is a non-empty list? Well, that we would expect assert to print F, because isEmptyList is not empty. Of course, it's called a non-empty list. So let's run this. OK, well, let's take non-empty list here. I don't know what it is, so we'll make it an I. Now, it is T and T, but it's not what I'm expecting. It's not what I want. I want it to print out T and F, because if I assert isEmptyList on a non-empty list, it should actually fail. So that's no good. So why don't I change this? The problem is that I'm hard coding this here. So whenever I have a hard coded thing, but I want to actually have two different options, then what I want to do is move the hard coding up to an abstraction. So at this point, I now have what I'm expecting, a T and an F. But since we're writing tests, we don't really want to have a whole string of T's and F's and go visually figuring it out. We just want a long string of T's. So rather than using assert, which we've said up here, prints T if the value is true, we want to write this other one, which is called refute. So refute, if we look at it, it basically takes the same thing, except if it's right, we want to print an F. And if it's wrong, we want to print a T. It's basically just the opposite of that. OK, so what happens with refute? Well, refute looks a lot like assert, but I can't just call the Boolean because that doesn't do me any good. I'm still getting that F. I want refute to give me a T. So again, we've got an abstraction problem. So we're taking that Boolean and we're calling it. But our true always prints T. So what we're going to do is we're going to actually comment out our refute and work on assert a little bit more. Actually, we're going to comment this too and move back to assert. And we're going to make a little refactoring on assert. So instead of having the Boolean, we just execute it and it prints T, what we're going to do is we're going to take that choice and move it into the Boolean. So it would be nice if I could say that my assert, I want to take this and bring it down here. So I can grab that, put it there, grab that, put it there, and then I don't have to call it here. And so what I want the Boolean to do is take a true case and a false case and just return me the true case and the same with false. So let's replace false. So the false takes a true case and a false case and returns me the false case. And then I execute it. So I've basically just moved abstraction over to the Boolean and now I'm bringing the concrete stuff back in and abstracting that choice out. So now I get an F which says that my false is what I wanted because I'm visually verifying it now. So this works with assert. So if I bring up refute, I would expect refute to print me an F and I would expect refute of false to print me a T. Well, it's not going to. We actually need to bring... We really... Refute is just like assert except opposite, all right? So I should be getting TFFT because if we look here, we get a T, FFT. And I do, which says to me that everything's kind of working for me. So let's take a little brief look at this. Well, true is a function that takes two arguments and returns you the first argument. Does that sound familiar? Well, it should because this is K from up here. Takes two arguments, returned me the first one. So if I run now, I still get the TFFT. Now here's something that's going to blow your mind. Look at this. What is this function inside? Well, this is a function that takes an argument and returns an argument, right? Well, we've seen that before, right? I keep saying right because I'm hoping that it is. Well, that's just the identity function. So false is something that takes the true case and returns the identity function. I think if I run my test and see it, TFFT, which is still good. Now here's the thing, so that's unnecessary. We don't have to actually care what that true case is. So false is a function that takes something and no matter what you give it, it returns you the identity function. So you could kind of think of it as a constant function that always returns I. Well, we know what a constant function, how we can create a constant function. So this is actually K passing I in. So no matter what I now give to it, I'm going to get the identity function back and then I'm going to get that. And so TFFT, love, that's my favorite part of this whole talk. So let's comment these out. Our assert and refute are now working and that's wonderful. But let's do one little more refactoring. I'm going to do a little bit of moving of code. Look at a certain refute. They're exactly the same. The only difference there is one passes in a different true case, one passes in a different false case. Now, Sandy yesterday had talked about how when you are doing refactoring and you're creating abstractions, you want to find the pieces that change and take those and extract them out and then pass them in. Well, we're going to do the opposite, which is we're going to find the things that are similar and we're going to extract that out. One gives you an abstraction that's a little bit higher. One gives you an abstraction that's a little bit lower. So we're going to take this idea of taking a boolean, a true case and a false case and executing which one comes back and we're going to do it with a function that you may never have seen before, but I'm going to make it up. I'm going to make it up. I'm going to call it if. So it takes a true case and a false case. Look at that. Three arguments, two, three. And what does it do? Well, it's basically doing this, except instead of having them hard-coded, we just use what's passed in and that allows me then to make this as a function call. So now I'm calling this if function, passing in the boolean, passing in what I want to have happen if in the true case, what I want to have happen in the false case and then let me get rid of that comment. Let me run it. I should still see tfft and I do. So now I've got a really nice kind of abstraction, this if statement. So the last refactoring that we're going to do is around the assert and the refute method. So if we look at them, we still see that they're kind of the same. There's only one small little difference. So it sure would be great if I could have refute defined in terms of assert. Well, luckily, not going to hold you in too much suspense we can. So what I want to do is say, refute is just the opposite. It's basically the same if I could take the opposite of the boolean or the not. So let's hold this real quick and let's build a function called not. So what not does is if I take assert and I do not true, I should get the opposite in f. If I assert on false, I should get a true and the same with refute. So if I change this to refute, I should get a t. So my knots are kind of the same. I've been running off t, f, f, t. Well, when I use a not, I get f, t, t, f. If I run this, of course I get uninitialized constant not. And so I can create it. Well, what does not do? Not takes a boolean. And what is it supposed to do? Well, it's supposed to say if it's false, return me true. If it's true, return me false. It just swaps them. Well, luckily I have a function already called if, convenient. So if my boolean, we're gonna see this pattern a lot where you take if with that and then what you put into here is the true case. Well, I wanna return false. And in the false case, I wanna return true. And now if I run, I get f, t, t, f, which is what I kind of expect. So now I know that, I know that not works. So now I can come back down and get rid of these and run these tests. So now I'm back to t, f, f, t. So I'm still with assert and all of that. But if I bring not up just a little bit, at this point I can redefine refute as assert not my boolean. And at this point I'm still at t, f, f, t. So I've got some nice boolean operators here that I can use, but that's not really what we wanna build. We really are looking to build lists. So let's come down here and talk about lists. Well, make sure these are still passing. Yes, they are. That's great. So it's one thing to say that a list is empty or not, but what happens, I wanna be able to add things to list. That's really kind of the important part of all of this. So I'm gonna get rid of this non-empty list because that doesn't do us that much good right now. But what I'd like to say is wouldn't it be nice if I could make a list that has the true value in it? So I'm gonna make up something called add the list. Gets a true and I'm adding it to the empty list. I get to define everything. Now just as an aside, this is a technique called programming by wishful thinking. This is the way I write all of my code. I think it is a core part of certain styles of test-driven development where you basically write what you wish you had and then you implement it until it's actually there. So some might say I live my life that way, but that's a whole different talk. Okay, so let's look at this. What does this do? Well, we don't have add to list and I don't even know anything about it. What do I know about add to list? Well, the way that I can find out things about it is to write tests. So what I can say is, well, is this list empty? Well, it's not. It should be a refute. So if I add an item to it, I shouldn't have an empty list anymore. So if I run this, well, I get my initialized constant because I just wish it was there. So let's come up here and build add to list. Well, what do I need it to do? It has to take an element and it takes a list. And well, I think I can just return true. Helps if I have extra there, aha. So I return true. It didn't make my other test pass, but it still makes that first one pass. So it doesn't do me that much good. But what if I return my list? Now, what if I just return empty list a little bit better? What if I pass? There we go. Now I'm marking empty list is true. Add to list is false. So no matter what, I now can check whether or not something is an empty list or not. And that's important. It's important to be able to say that. And so if I make something that's, I'm adding false to the front of that, oops. I would expect to be able to refute that as well. So if I have a two element list, then I can refute it. So at this point, I now can tell whether a list is empty or not. And that's great. It's kind of fun, but might not be exactly what we want. So it also is good if I can tell what the list was that I added it to. So just telling whether it's empty or not is not that great. But I wanna be able to do, if I look at a list, well, a list looks like this. It has the value true. And then it has the rest, the other list that I added it to has false added to another list which was true with a bunch of other stuff on it, the rest of the list. So I'd like to come down and I would like to actually be able to say is what's called the tail because a list is like a snake. It's got this thing on the front and then the rest of it, which is another list. So I'd like to be able to do something like this. Well, the list that has one item in it, if I look at it here, I added true to the empty list. So I should be able to assert that the tail is the empty list. Because if I only have one item, then the tail is the empty list. Of course, I don't have anything like that tail. So I'm going to do something here and say, well, what does tail do? Well, it takes a list and well, I'm going to actually return the empty list. Awesome. So now I'm passing. So now every list is a one element list because the tail always is empty. That's okay. But I would expect to not see the tail of my two element list up a little bit. That's wrong. I would expect that the tail of that to not work. So I've got an F, I need to fix this. So I want to mark and maintain this mark that something's an empty list, but I also need to pay attention and here on add to list, I want to keep track of that list that I added to. Well, it would be wonderful if I had a way to keep track of it, a tuple of some sort. Because then I could just take the first element to get whether or not it's an empty list and the second element to be the list that I had or that I started with. Well, we don't have anything like that, but luckily we can wish it into being. So I'd really like to do something like this. Let's make a pair. At that point, the tail will be the second element. If it's an empty list, I won't just return that. I'll actually return the first element of my pair. Empty list now takes my list. And the empty list is just going to mark itself. I don't know what, so we'll just use identity. So empty list is a pair of true, which is the marker that says I'm an empty list and the identity function, because why not, is empty list grabs the marker, returns it, add to list, constructs a new pair that has a marker of false. This is not an empty list anymore and a list. And tail grabs the second part, that list that was still there. And okay. So if we run this, we got lots of failures because I have an extra thing here. There we go, uninitialized constant pair. Well of course, because nothing is real. So let's work on pair. Pair is really nice. What do I know about pair? Well let me create a couple of them. I have a pair of true and false, and I have false and true. What can I know about these? Well, I should be able to assert that the first part of true false, that should be true, I should be able to refute the second part of true false. I should be able to assert the second part of false true and refute the second part, or the first part of false true. Yay auto completion. So this makes sense, right? So I'm just writing the test. This is the way I want pair and first and second to work. Of course I don't have pair, so let's talk about pair for a second. So pair, it basically takes two arguments, which we've seen, and it has a couple. First takes a pair, returns the first argument. Second takes a pair, returns the second argument. These sound pretty familiar. They sure sound like kind of like true and false to me, which we decided was K and K of I. Well, so let's write this. This takes a first element and a second element. I don't know what it does. First takes a pair, oops, I don't know what it does. Second takes a pair, I don't know what it does. Now let's look about first and second. Let's pretend. Like what if pair, what do I know about pair? I know it's a function. So I can call it. Wouldn't it be sweet if I could call the pair and give it a function that picks the first one out? So what if I could give it a two argument function and return the first argument? And then here, return the second argument. So basically pair is a function and I'm giving it a function that takes two arguments and picks out the first or the second. Well, that would be great. How do I do that? Well, pair, what do I know? I know it's a function, so gotta return a function and it's gonna take, that function takes another function, a function that selects between the first and the second. So I'm gonna call this selector. Now what I need to do is call the selector passing in the first and the second. It's a little nicer. And if I've typed it correctly, pair now works. This, I find one of the most awesome parts of all of this because it's so much redirection and I'm so happy. Here's my other cap pistachio. Ah, time, I would wait. Can we skip ahead to where it says pistachio? There we go, this is my other cap pistachio, yay. Okay, so back to pairs. Well, we're gonna, of course, simplify this. What is this, anybody? Takes two arguments, return the first. K, it's around our tests, still passing. This takes the two arguments and returns the second one, what is this? K of I, look at that, all passing. So now, look at, that's pretty fun. So now if I come here, oops, it would help if I actually pulled these out. There's my lists. What's failing? Shit. Oh, did I say that out loud? So add to list, so empty list takes a pair. Add to list creates a pair. Empty list takes the first item of that. Tail takes this, and then is empty list takes the list? Where are we failing? This is always the bad part of coding. Say that again? Thank you. Oh, it's always the horrors of live coding. Thank you very much, give it up for the him. Okay, so now we can actually tell what the rest, the tail of our list is. So what's left, well, it sure would be grid. Let's create another list for ourselves which gets the false with an empty list. I'm gonna move this up here. So list false is one element list that has false on it. So let me, I should be able to grab the first element because of course it doesn't do you any good if all you can grab is the rest. So now we've got tail of the snake, let's use head. So I should be able to assert the head of the list true and refute the head of list false. And what really just to make it sure is I'm actually going to assert the head of the tail of list false true. So now I have a two element list. I'm gonna take the tail of it which should be true false or true and then take the head of that. So we've seen this before, uninitialized constant. Head, wow. We get the same problem that we had with the other one is we're not keeping track of the element. So we can't really make a three pull. We could but we're not going to. But what we can do is instead of just having this list let's make it a pair of the element and the list. At that point we have to have this be a pair of I and I. There's a few things that we could do to make empty list better but we don't care that much. Is empty list still takes the marker? We're always maintaining that marker. The tail is, what is it? It's the second element of the second element. So I have a pair, it looks like this. Marker, comma, element, comma list. So the second item is the node. The second item is the list. Head in this case, oops, takes a list and it takes the first item of the second item of the list. And we're all passing and now we can pull the head out and there's one little thing we'll do. This is ugly, naming is super important and if I come back to this in like an hour I'm gonna have no idea what I just wrote. So let's extract that out into something like list node. So if I give it a list it actually just returns the second item and once I'm there I can just change this to list node and this reads nicer I think there and I'm all passing. So what I've got now is I've got a list. I started, let's recap a little bit. I started with these two lambdas, I and K. The identity function and I'll let you in on a little secret this is actually called the K combinator if you ever like actually go in and look at lambda calculus and combinators. There's a guy named Reg Braithwaite who wrote a great book on combinators that are worth doing it. This is also called the Kestrel and this is called the idiot bird. So we started with I and K, it is called the idiot bird because it repeats back to you everything you said. All of the combinators have names. If we had time we would do composition and composition is called the bluebird. Combinators are awesome. So we started with I and K, we built up a Boolean structure, we built up assert, we built up if, we built up true and false. We then got and we played with not. You could see probably with if that we could build up and or and all of these things. We made pairs, we have tuples now and with tuples once you have tuples you can make lists. Now imagine this, imagine you took lists and you had the length of the list be numbers and now you have numbers and once you have numbers you can assign characters to them and once you have characters and lists you can make strings and you can build up the entirety of everything with just these. So let's get back to things that are relevant to your day to day life. Hope this was fun. Here is your treat. A pictures of both Squeaks and Pistachio. Thank you.