A book club for developers.
BookBytes is a fortnightly (or biweekly) book club for developers. Each episode the hosts discuss part of a book they've been reading. And they also chat with authors about their books. The books are about development, design, ethics, history, and soft skills. Sometimes there are tangents (also known as footnotes).
(Intro music: Electric swing)
Hello and welcome to BookBytes, a book club podcast for developers. We’re continuing “The Imposter’s Handbook: A CS Primer for Self-taught Programmers” by Rob Conery, and this week we’re going over chapters 12 and 13 which is Functional Programming and Databases. I’m Adam Garrett-Harris.
I’m Safia Abdalla.
I’m Jason Staten.
And Jen, this week, is very sick. So, as she says, “Too sick to knit.” So she can’t be on the show today but we’ll carry on without her.
All right, so I was pretty excited about the Functional Programming chapter, what about y’all?
That’s definitely where I spent the majority of my time between these two chapters.
I found the Databases chapter a little bit more intriguing, but I definitely did like the way that the Functional Programming chapter was set up, like the four themes that Rob separated it out into.
The four themes? What was that?
Yeah, so if you’re reading along with us the four themes are described on page 291. They are the theme of immutability, purity, ideas around side effects, and then ideas around currying. And the book kind of went into each of these topics a little bit further in that chapter.
Nice, and yeah, this is based on Lambda calculus which we talked about before, but honestly, the only idea I think that, for me, carried over from Lambda calculus is kind of everything can be a function and you can pass around functions and you use functions a lot.
Functions as values rule of thumb.
So in asking about the background that both of you have, have you done much in the line of functional programming? Or tell me about that experience you’ve both had.
Yeah, So I can talk a little bit about it. In University, we were working with a language called Racket/Scheme which was designed to be a function programming language with a Lisp-like syntax.
Oh, that’s super cool that you’re using Elm.
Yeah, I was gonna say, “Yeah, it’s been interesting.” It was my first time using that language and especially in like an application or like a software that people use on a day-to-day basis. Like, you know, like, not just like, a pet project or something like that. So, yeah. It’s been interesting learning it and figure it all out and stuff. It’s definitely like a mind shift.
Yeah! Yeah. It’s so weird. It doesn’t let you do any side effects at all, but side effects still have to happen, but they’re all taken care of by the Elm runtime.
Yeah, and for me personally, the syntax was one of the hardest things to grasp, and also just its strictness around typing. Elm has a lot of type inference built in that’s designed to kind of avoid errors that might come up in runtime. So, you know, you have strict types to find for something that are going to capture all of like, the annoying corner cases and like flukes that you get when you might be running a program and give you a chance to deal with those. So navigating its strict typeness and, like, building a good type model for the application was something I had to figure out, too. ‘Cause it was like you have to be like, very strict and precise about types and make sure that it all worked well in the Elm model. I don’t know if I’m explaining this well.
Yeah. That’s actually one thing that I don’t feel like was brought up a lot within the book, at least as far as I’ve seen, and I don’t know if there’s a chapter on it, maybe season two, it is talking about static typing versus dynamic typing, right?
Your mental concepts and approach to handling problems is definitely different, but that’s awesome that you’re using Elm. It’s something that I’ve only tinkered with on the side. So like, to hear the experience of somebody using it in a production, like I'm curious how you’re perceiving that within Elm as we kind of, hit through some of the topics.
I’d thought the promise was that if it compiles in Elm, it just works.
Oh! I have fun stories about that! (laughing)
There have been a few occasions where… So the part of the codebase that’s written in Elm is not the entire codebase, it’s sort of like a small chunk of it and it sits at the intersection between two other codebases that are not written in Elm, and that are not as strictly typed. So there are situations where Elm is communicating with an external system and that external system unexpectedly gives it data that causes Elm to bork.
So it’s not in within Elm itself, it’s within its interfaces to the outer... To other parts of the codebase. I don’t know if that made sense.
Yeah. My understanding was that when you’re getting data from the outside you have to take care of every possibility and handle every case.
Yeah you have to write decoders-
To decode the data that comes in, and then encoders to send it back out. And those are where a ton of the bugs happen.
Gotcha. Okay so, as far as my experience goes with functional programming, about 6 years ago I tried to take a course on Scala on Coursera-
I think they’re starting that up again.
Yeah! So I’ve written some functional programming in production. It was just, the same kind of thing as you, Safia. It was just a tiny little part of… I mean this was a really tiny part of a website. But-
It was fun.
I know Elm recently released their 0.19 version, which is like a long awaited update, and I was exploring some of the things they’d laid out, and they do have an example codebase up that is a full-on web app written entirely in Elm, and I will try and find the link for it and put it in the show notes for people who are curious as to what a web application that is written entirely in Elm would look like, and not just…
As like, a tiny, auxiliary thing.
Yeah, I think it looks really beautiful and they’ve got the built-in formatter, and the way everything lines up is really cool.
Yeah, when it works with you and when it’s not super stressful, it is really great. And I guess that’s just software in general, and programming. When it, like, you get it and your mind is flowing and you’re like, in tune with everything, it works well. But yeah, when you’re trying to figure out how to write a decoder to cover all the cases, or something …
That’s not super fun (laughs).
(laughs) Yeah. What about you, Jason? What’s your background?
So, I have less production functional experience than both of you, and so I have, I have a little bit of Elm envy, I guess. But I have spent a good chunk of time doing some Clojure work in the past. I studied the “Programming Clojure” book and then followed it up later with “The Joy of Clojure”, which was probably one of my favorite programming books that I’ve read, just because it really showcased how thought-out the language was, and how much it built on pre-existing concepts. Everything that they were going through in the book where they talked, say, about software transactional memory, they went and said, “Well, here’s the whitepaper for the thing.” And it was written back in the 70s, or something like that, and so like, it’s not necessarily all these new ideas, but they show how like, Clojure took these old concepts and applied them to a modern Lisp. And so I’ve spent time with that.
And yeah, it’s definitely a common pattern to see now. Today, I actually found out that Internet Explorer does not support object.assign which is-
Kind of the old-school way of doing an object spread.
What version of IE? Is it just prior to Edge?
Looks like all of them. Yeah, prior ot Edge. So all the way up to IE 11.
Good thing for polyfills I guess.
Yeah. Yeah, for sure. And it can seem annoying, too, that you have to try to make the compiler happy and a lot of times we tend to think like, “Oh, the compiler’s complaining or yelling at me.” But it’s… It’s forcing you to do something you should be doing anyway.
Yeah, that’s a good way to think about it, it’s doing that work for you. Yeah. All right. So that pretty much covers immutability, I guess. What about purity?
So I think it’s coupled this way in the book, and I think it also makes sense for me, personally at least, to think about them together. Purity and side effects is things that go hand in hand. So purity is the notion that your function only relies on data that it’s given. So it’s not accessing any like, global data or things like that. The parameters that you pass to your function are all the parameters it needs to do its work. And then side effects are functions. The fact that the function will only operate on the parameters that you give it, so it’s not going to mutate some global object or some other data element that you didn’t give it.
I try and do this in general, because I think it makes code a little bit easier to test, and this kind of relates to the discussion that we’ve had in the last episode, is that when you write code with the intention… When you write tests first or when you write code with the intention of testing it very well you end up writing functions that are purer and don’t have side effects because those are the functions that are easier to test. So that’s one of the reasons that I employ that technique. Not really relationed to functional programming at all, just related to how easy it is and how safe I feel using that function and testing it.
Yeah, definitely. I think if you followed test driven development you’re more likely to do this ‘cause it’s easier to test pure functions.
Purity is one of the concepts that I wish that he would have put, actually even before immutability.
Because, I mean, like, immutability is important, but I think having a function that works more like the mathematical concept of a function where given an input, you always get the same output out of it, like that being a pure function, that’s what you get in math. Like, you don’t ever have to worry about some other thing changing your f(f) that you’ve written in math. And that was probably the most eye-opening concept for me when learning about functional languages long ago; that all of your state is just things that are passed in to your function. It’s very explicit and obvious where that’s coming from, versus even in an object-oriented language…
Like, I had the example once of a person object and maybe you had a method on that person of “Is old enough to drink” or something, and that function itself, or method on that person, would be entirely dependent on the person’s age which is probably not something you would pass into the method itself but instead you would read off of that object. And so the scope of code that you have to concern yourself with becomes a greater amount versus if everything is just within that single block, it can make it easier to test as well as read. And I know like, saying “code is easier to reason about”, that is a dangerous term to say, but in short, like, sometimes it can be because your context you have to be aware of is smaller.
So why do you say it’s a dangerous thing to say? I agree that it’s become kind of cliche.
I guess maybe not “dangerous”, but cliche is also very opinionated, too. In terms of what’s easier to read…
Yeah, like functional programming can be written in super terse ways as well. Like, if you go and look up point-free programming, that is a realm of like, making super terse code that is all just data transforms. And in one person’s mind that can be super readable and they know that data’s just flowing through all the transforms, but somebody else would see it as totally unapproachable because they don’t even have a way to inspect in between what’s going on in the functions. So that’s more of what I mean about being dangerous. So maybe it’s just a subjective type of view.
Yeah, I guess it could really make people feel excluded if they look at it and it doesn’t seem easier to reason about to them, because they don’t have the same context and experience.
And Ramda is awesome because you can do all of these really cool functional things with it, like it’s got currying built in, which we’ll cover in a just a moment, and other niceties, but it also is a way to make a codebase that somebody who’s unfamiliar with it can take a while to actually go and grok. So you also have to consider, like, if you’re working in a nonfunctional language and you’re writing things in an attempt to be super functional then you may make your codebase unreadable by anyone but you.
Yeah, good point. Okay. Yeah, so what is currying?
I went and did some googling, too because he talks about currying and then a little bit later into the chapter Rob actually mentions Partial application and I was not totally clear on the differences between the two of them and now I think I have an understanding.
Oh yeah, I see on the Wikipedia page that “currying is related to, but not the same as partial application.*
Yes. They may bring up the same concept and it’s similar. So the shortest description I could think of is like, currying is a way of taking a function that may take three arguments and converting it to a function that takes one argument, and then returns a function that takes one argument, and returns a function that takes one argument until ultimately there are no more left; Whereas partial application is a way to take a function of n arity and make it a function with less than n arity. So like,it’s applying one function but it’s not necessarily returning back a function that only takes a single argument after that.
So arity is the number of…
Arguments to a function.
Okay. So currying, it only does one at a time?
So currying, it will take an n arity function and turn it into a function that takes 1 arity. It will take n levels deeps. So an n arity function into an a 1 arity function n levels deep.
Oh good. Good way to make it…
And a partial application takes an n arity function and turns it into a less than n arity function. So it doesn’t necessarily return back a function that has just one.
I wish when I was applying for jobs I could turn in a partial application.
That is such… I’m really glad you shared that, Jason, because I actually used the second technique, partial application, a lot in my code and I’ve always called it currying, ‘cause I thought that’s what it was. Now I realize, it’s not what it is. It’s… ah, thank you.
So what happens in Elm or other ML-type languages is they curry the function for you, that’s what the compiler does for you, where you can go and say, “Add (A-B) equals” and then “A+B.” That, by the compiler, get curried into a bunch of single arity functions whereas partial application is you actually invoking those until you ultimately get the result. So…
Yeah. Words are hard.
Yeah! Especially when they’re so close.
I- Is ELM that way? Where you don’t have parentheses?
You don’t have to, there are cases when I have done it, but I think that’s because the type of data that I was passing made it so that you needed to separate it, but usually there’s no parentheses or anything, it’s just like a space or you can use the pipe command, like the ones we saw earlier in the Elixir examples he had.
To have to invoke a function that many times.
I know that he was, like, trying to prove the point though in a familiar language though.
It shows what it’s doing, but writing code like this is a way to scare people away from your codebase.
So if you want to scare people away, use functional programming in a language that’s not purely a functional programming language.
Or I guess, maybe even in a functional programming language, too.
I was gonna make a joke and say if you want to scare people away use function programming.
So the book mentions this line from Douglas Crockford about monads where if once you understand them you lose the ability to explain it anybody, which I guess you don’t really lose the ability if you just now understood it for the first time… But anyway, I hear that all the time, do either of y’all have the ability to explain monads?
(laughs) So, I mean, I uh… A monad is a monoid in the category of endofunctors, right?
Which there is a-
Oh! I totally get it now!
You’re not up to date on your category theory?
So there is a guy that does a course on Haskell and category theory called “Bartese … “ Something or other. I need to go and look up the link on it, but he actually does an explanation on Quora, like, of what that actually means, because somebody on Quora was like, “Is this actually true?” And he gives the drawn out definition as to like, why that actually is. Like, what the category of an endofunctor is, and I will not try and explain what a monad is within the podcast because it’s definitely going to be wrong, and so I won’t go there. But I do have some feedback on some of the stuff Rob wrote, actually. With regards to: first, the select query he refers to it as… So select query, I think it’s initially written, in the hard copy of the book on 305, and he calls the function curried, but if you notice the second function deep within it-
It actually takes in two arguments.
And so that is not curried, and so… I was like, “Wait a second…” And I only figured that out after reading like the currying versus partial application thing and I was like, “No, it’s gotta be one! Otherwise it’s not currying.” So…
I’ll have to submit that in an errata and see.
Yeah, I also feel like there’s an errata on page 304 with the dancing with wife function, or the one where he’s currying the date night function and I think at one point the arguments get passed in in the wrong order.
It’s supposed to be Who, What, Where but then he passes in Dancing, Wife, Club.
So the output, actually would have said, “Out with dancing, having fun wife at club 9.”
It’s like a MadLib!
Yeah! Yeah, just put noun here.
So anyway, what else about the select query example?
So this is not specific to the select query, I did actually go and rewrite his Monad version of it because I didn’t like it and he asked for a new version. So I write a gist of it. And mostly I didn’t like that he went and wrapped his concatenation of strings within the maybe when it really wasn’t necessary. Even he brings that up, that it’s not necessary here. He’s like, “I could just use a template string, but I’m gonna go and this inside a whole bunch of maybes.” And I think that that is not right.
That is a case of like, usening a construct that you don’t really need. And so like, that’s the way that you can go and make codebases unapproachable.
So, don’t just go and use it because it looks fun to use. I also don’t like his maybe implementation because value winds up just being like a ternary that produces an empty string out of it.
Yeah, I was wondering about that.
Yeah, and so I will have to like, send you my gist so you can take a look at that. Not that it’s necessarily a whole lot better, but it doesn’t do that. It actually gets mad at you if you try and extract a value out of a nothing type maybe. So…
So for the listener, the Maybe is one of his examples of a Monad and it has basically three methods on it, is Nothing, the Map, and Thal. Oh! And also, Of?
Yeah. Of is a static method.
So It is a way to take a raw value and convert it into a Maybe.
And his functor example of a monkey. First, monkey is kind of a weird name for a class. Like I know it was, maybe, trying to be nonsensical but monkey doesn’t help get the point across for me because it kinda makes me think of like, when we learned object-oriented programming and, you know, monkey derives from animal. Or like, monkey extends animal, also not a good example of OO.
So weird choice of name. And secondly, his Map implementation on it is wrong.
So his Map should be returning a new monkey with the results of the function past a Map applied to the value.
Because a functor is something that implements Map or fMap in Haskell that takes in as is it, one argument, the… A function that can transform from a type of A to B, and then it takes a functor that holds an A and returns a functor that holds a B is the type signature for the thing. So the important thing with a functor is that whenever you call Map on it you always get a functor back out. You get the same functor back out. It might have a different type that it holds within it, but-
Right. So it’s like when you run Map on an array you still get an array back with possibly different type inside of it.
Exactly. An array is a functor. So, it’s a way better example that opened my eyes when I first heard it. It was like, an array is like this container that you can go and you can call Map on it, and the function may be called one time, it may be called zero times if there’s nothing in the list. It could be called 100 times, it doesn’t really matter. All you have to care about is that you’re going to get an array back from that thing that, if you want, you can go and call Map again on it if you want to. Over and over and over because it always returns back a Map.
When you call .then on a promise … Then the result of that gives you back a promise. And why it’s not truly a functor is because it goes and unwraps if you return a promise within that then block, like, it goes and flattens it out. So that’s what makes it not actually a functor.
But it’s kind of like that. Like, if you’re not doing the type where you actually go and return a promise within that then block, and it’s not flattening, then that is functor-esque.