Functional Programming Through the Lens of a Philosopher and Linguist
Lars Jensen: I'm Lars from the GOTO team, and I'm joined today by Anjana Vakil from Observable. How are you doing, Anjana?
Anjana Vakil: Hi, doing well. Thank you. Yes, hanging in there.
Lars Jensen: Yeah, I think we all are. What is it that you do? I just briefly mentioned that you're with Observable. But do you want to tell us what you do professionally?
As a developer advocate, I work with the community to try and help get folks up and running with the platform and learning new skills. And also to bring back feedback from the user community to the team and make the product better.
From Linguistics to Programming
Lars Jensen: That sounds really interesting. I'll have to spend a little bit more time digging into it. So I'm here talking to you today about functional programming.
Anjana Vakil: I love talking about functional programming.
Lars Jensen: Actually, I want to start somewhere else. You have a background in linguistics and philosophy, right? So how do you go from linguistics and philosophy to computer science? And how do you think that has affected the way that you think about programming and how you develop software?
Anjana Vakil: I had a pretty wandering path. I majored in philosophy in college, and I was always really fascinated by foreign languages, by the different ways that humans can express themselves and by the kind of philosophical questions that raises around what is being, and what is identity, and what is meaning and these kinds of big picture things. I've always been a big fan of that kind of big-picture thinking.
I really was motivated by wanting to learn as much about the world as possible, wanting to learn as many different languages as possible. I ended up getting into teaching English as a foreign language for a long time. It took a lot of years, spending time around the world, teaching different folks English as a foreign language. Eventually, I got really interested in the field of linguistics, in the scientific study of language, how it works, how we learn it and how different languages do things differently.
I found out that there was a field called computational linguistics, which I did not know existed until late in my life. I found this super fascinating. Computational linguistics is basically a big umbrella term. It refers to a lot of different stuff. Everything from using computational methods, and data, linguistic data, statistics, machine learning and similar, to understand language better.
On the other hand, to use that knowledge to create better language technologies. Things like speech recognition, which I was particularly focused on, or text-to-speech synthesis or language modeling, predictive texts when you type in words on your phone, all of that kind of human language technology. I just found that field super fascinating. I went back to grad school to study that. And in the course of doing that, I had to learn to program. I really started doing more software development through the course of studying computational linguistics, and I basically fell in love with the software.
I found I really enjoyed writing the code and the software that I needed to do my linguistics research a little bit more than I enjoyed doing the actual linguistics research. So I gradually moved into the software field and from there, I just found I really had a passion for helping people learn different topics in computer science, especially in programming paradigms. That's my kind of philosophical, big picture thinking about what does it all mean, and what is the world? It really kind of connected when I learned about different programming paradigms and different ways of conceiving of a programming language.
Getting a little bit into programming language theory and ideas of different ways we can conceive of a computer program, what it is, what it's made up of, and how those things interact with each other. I think that philosophical background, and this idea of “There are different ways we can say things and do things” from my linguistics experience really informed the lens that I have on thinking about different programming languages and the different ways that we can develop models to think about computers and computing and writing programs.
Lars Jensen: It's really fascinating to think about. I think one thing from one of your conference talks that I saw some time ago really stuck with me. If I remember correctly, you said that programming languages are more for communicating with other people and it's just a side effect that we have computers running those instructions. I think that was a really interesting observation and I guess that's your linguistics background showing through a little bit there as well.
Anjana Vakil: A little bit, but I can't take credit for that idea. It's certainly something that folks have discovered through decades of computing, seeing how software evolves and how systems develop and grow. And that essentially, over time the act of doing computing and of advancing the state of the art, of creating ever more complex programs, ends up really being more about the people that are involved than the computers.
There’s this amazing quote about humans and computers. I want to say it's in "Structure and Interpretation of Computer Programs" but I could be wrong about that. It says: "[...]programs must be written for people to read, and only incidentally for machines to execute." It's only incidentally, a sort of side effect, that you can run it on the computer and execute your program as intended.
I think this is something that people much smarter than me have said and thought, in the past. And I couldn't agree more. I think what's really fascinating about the practice of software development and the practice of creating really complex programs that can be maintained over time, that are readable, that are understandable to other people, is really understanding how we all understand code. And trying to make code that's easier to grasp, given a particular mental model of how things are working.
That's a huge problem and something we're all gonna be working on for many decades to come, I'm sure. But it's something that I find fascinating, really thinking about. Computers are simple beings, they do what we tell them. They don't really care how we say it, or what art we use to say it with. They don't really care about an elegant program that expresses its ideas in simple mental concepts. They just care about the instructions we're giving them and what they're supposed to do.
But as humans it can make a huge difference. If we're looking at some machine code in binary, that's not very useful for us in terms of changing it and morphing it to our use cases over time as they change. Whereas, if we can write code that is expressed in such a way that it's easy for a newcomer to the codebase to understand, that it's easy for someone to remember what they wrote 10 years later, then we can create really powerful, expressive systems that are made up not just of the code itself, but also of the humans that are touching that code, reading it, working with it and having to maintain it.
The Human Performance Factor
Lars Jensen: I completely agree. I mean, it's one of these things: the more time I spend writing code, the less I'm starting to care about performance and correctness and things like that. And the more I care about: Is it easy to read? Do I understand it? Will I understand it next week? Will the new guy that we're onboarding understand it? Will I need to be around to maintain this or could other people take over this code? Those sorts of factors are becoming much more front and center for me. So I completely agree with you there.
Anjana Vakil: Exactly. And I think of it as factoring that into when we're thinking about the performance of our code. There's a great talk by the developer of this game Braid if anybody's played that, where he talks about the human performance factor. There's a measure of performance for your code where we're talking about how much time does the program take to run? How much space does it use and memory?
But there's also the question of how much time did it take you to write that code? How much time did it take you to make an update when you needed to? So what is that human performance factor? And I think that's an interesting lens to take on, reconsidering how we frame writing performant code. If it's performant for the human side, as well as the machine side, then we're doing great.
Lars Jensen: Is that Jonathan Blow by any chance I think?
Anjana Vakil: Yes, exactly. Thank you.
Lars Jensen: Right. It rang a bell when you mentioned the game Braid. He has a lot of interesting points I think. We're getting a bit into the weeds here, but I hope you don't mind.
Anjana Vakil: Please, just here to chat.
Lars Jensen: Yeah, exactly. That's the thing that we’re doing.
Anjana Vakil: Hallway nerd out is what we're doing right now.
Lars Jensen: I mean when you mentioned human performance, it reminds me a little bit of another speaker that we've had at our conferences a few times before, Adam Tornhill. His whole idea is that all of the data we have in Git is also kind of social data. It tells you who worked in which files when, and how often are we needing to change this file. Based on that information, you can tell a lot about the codebase and the people working on it. And use that as a sort of guiding factor to figure out which parts of the code are really complex and need to be changed often. Maybe that's a good place to focus when you want to refactor.
Whereas let's say you have this other part of the code that is messy, people might scuff their noses at it. But you know what, it never needed to be changed, it changes once every few years or so. So it's okay. But sort of considering the social factor of the information we have in Git, I think, is a really fascinating concept as well.
Anjana Vakil: Absolutely. I couldn't agree more. At Observable, we're doing data visualization a lot and it's really fascinating what you can see. The GitHub API gives you so much information about different open source projects. So much of this information about who is involved, which files are changing, which areas are kind of under active in development, and which are more stabilized, as you say. And then being able to pull that into a visual representation, where you can navigate through and see who touches which part of the codebase, which files are associated with which people and which parts of this are moving quickly, and which parts are stable.
Being able to visually see that is also a really great tool, especially when you're getting started in a new code base, trying to orient yourself. Trying to understand: What's the context here? What's been going on? Being able to look at that all with your eyeballs, instead of having to read through logs. It's a real leg up in terms of understanding a codebase and understanding how it functions. And the human side of that is the entire thing you need to understand there. So yeah, I couldn't agree more.
Lars Jensen: All right, I think that was a really fun tangent but it's actually not what I was here to talk to you about, although I think we could keep talking about this for a long time.
Anjana Vakil: Sure.
Lars Jensen: Let’s steer things back towards functional programming.
Anjana Vakil: Definitely, yes.
Lars Jensen: One of the questions I wanted to ask you: What defines a functional language? And then something you said, which rang really true with me is that it might make more sense to say, what features support a functional programming style? What features do you think a language needs in order to support functional programming?
Anjana Vakil: Great questions. The way I think about a functional language is a language that supports functional programming. Where if we understand functional programming, there's a couple of different ways to think about it. The way I usually think about it is programming with only pure functions. Pure functions being functions that take inputs and produce outputs. So they take in arguments and they return a return value. And that is all they do. They don't have any other side effects. So they're not changing anything else in the world, or in the program except returning their return value.
Another way people often think about it is programming without state. So instead of having values change over time in your program, and thinking about what the values are at any given moment, and how they need to change, given things happening in the world, is thinking about it in terms of data transformation, of data coming in and data going out. And there's really only the process of turning that in data to that out data and not any other kind of work to be done, not any other state to be changed.
So regardless of how you choose to think about functional programming, a functional language is one that supports doing that. You've got your pure functional languages, which completely constrain you, to working in that functional paradigm. You are not allowed to have impure functions, you are not allowed to have state in your programs in a pure functional language.
And then you have what we could think of as multi-paradigm languages where you can do functional programming if you would like to. And it has features that support that, for example, first-class function. So you need to be able to take functions and treat them as any kind of data that you would have as strings or booleans or what have you. You can take them as inputs to other functions, you can return them as outputs. They're just items in the world that you can work with.
Having first-class functions is really important. Sometimes having certain utilities can make things really easy like being able to do things like mapping and filtering over arrays or collections of data instead of having to use for loops or while loops to do stateful iteration.
I think in terms of these languages that support multiple paradigms, that's always a really great thing to my mind because it allows you to choose the right tool for the job. However, a lot of people that are working on problems that are especially well-framed as data transformation problems are huge fans of working in pure functional languages. So not only do I have the features I need to do functional programming but also the language is keeping me honest. It's keeping me from needing to discipline myself to write my code functionally. It's doing the discipline for me, and I don't have to worry about it.
I do actually like that because then I don't have to keep tabs on myself and make sure that I am using the more functional features and not ending up veering towards a more imperative style. Pure functional languages are great for that because I would say they have this added feature of you having no choice, an added feature of forcing yourself to live by the functional worldview, as it were.
Lars Jensen: I think personally, I fall more in the second camp, but for different reasons. I like having constraints. The same way that if a menu at the restaurant has too many options, then I'm paralyzed and I don't actually know what to order. But if the language makes opinions on how to do things, then it's easy for me to follow the rules. It's easy for me to keep things consistent. And I think for me, more importantly, it's easy to be consistent with how other developers are doing things.
Where in the multi-paradigm language, say something like Kotlin, where you can also do things in different ways, you might have Developer A who's really into functional languages, so he only does things one way, and then you have Developer B who's maybe doing things more object-oriented or procedural. And I can see that becoming a bit of a mess if you're not disciplined.
Anjana Vakil: Definitely.
Lars Jensen: So I personally prefer the opinionated constraint language. My day-to-day life, like my weapon of choice these days, is Elixir which I really like. So nice and pragmatic, like it's not one of those ivory tower theoretical functional languages. It's functional but without me needing to think too much about it, which I like.
Anjana Vakil: I've heard really great things about Elixir. I haven't worked with it too much myself. But everything that I've learned about it and how it works is fascinating. And the larger kind of Erlang world from which it springs is just, I think, a really amazing way of thinking about programming. I'm a big fan and I definitely agree. It also depends on what you're doing. As always, the cliché but also true maxim of programming is always it depends, right?
Especially when you're working on a large project with many different people that might have a lot of different opinions, as you say, like having the language or other kinds of systems of enforcing rules, style, all those kinds of things. There it can be really helpful just to cut down on going back and forth on those little questions of preference. But I think also, there are times where if you're working on something where perhaps you're trying to solve different types of problems in the same codebase, being able to move back and forth between different paradigms that fit better or worse and the problem that you're trying to solve within a single codebase, within a single language so that, you know, other folks on your team don't necessarily need to go out and learn a whole new stack. It can be useful.
But again it's a matter of trade-offs. So depending on how big your team is, depending on how complex the program is, I think the choices are always going to depend. But I totally hear you. And I totally agree that especially when you're working with a lot of different people, having really enforced opinions that the language will make sure everyone has to follow can be extremely useful.
Benefits of Programming in a Functional Way
Lars Jensen: Yeah. So what do you think are some of the benefits of programming in a functional way?
Anjana Vakil: So for me the main thing is predictability. It is so hard, in a stateful imperative program, to know exactly what the world is gonna look like when you run this code. You can have your tests, you can say, "All right, if the world looks like this, and this and this then does this run correctly?" You can think about all of those edge cases as you're programming, you can think about what if that thing is undefined, or what if this thing is a different size than I was expecting it to be? But you have to do all of that work to think about all of those ways that the world can be and you're never gonna do it perfectly. You're never going to think about everything. And your test suite is never gonna capture all of the different configurations the world can be in.
So if your program is stateful, and depends on that, then you're gonna have bugs. You're not gonna be able to predict what your program is going to do in a certain given situation. In functional programming every function is kind of simple, in the sense that it takes input and it gives you an output. And if you give it the same input, it's always gonna give you the same output. It becomes very predictable, it becomes very easy to know if these are my inputs, this is what my output is gonna be.
So that becomes easy to test, it becomes easy to enforce in some functional languages that enforce things like strict typing. You already know that it's not gonna be undefined. That's not ever gonna happen in this case because my type system has made sure of that. You can essentially narrow down to what you need to think about to this one function. You can test this one function, you can think about the performance of this one function. And you can know that no matter what else is going on in the world, these are the inputs it's gonna get, this is the output it's gonna give. And that's predictable, that's not gonna change because it doesn't depend on any state.
The consequences for debugging, testing, maintaining, changing and refactoring code are just amazing there because if I know what the outputs are supposed to be, for any given input, then I can take this one little modular function out. I can replace it with another one that's more performant, or easier to read, or whatever so much more easily. And I can predict the types of bugs I'm going to encounter. I can make sure I'm handling all of my edge cases, in many cases especially in pure functional languages. Languages will even complain to you and say, "Hey, you didn't handle this one case in your function, you got to handle it."
You just get so much more work done for you, basically, by the language or by the environment than when you're trying to work in a stateful way, and when you're trying to imagine how everything is going to be if that makes sense.
Lars Jensen: It fits very well with my own observations. I made the switch from object-oriented to functional probably four or five years ago now. Trying to reflect back on what has changed in my brain in that time, I think the biggest thing is that I have to fit less stuff in my mind at a time. You mentioned the main thing you have to care about in a functional language, or when you're doing functional programming is just what are my inputs, and what am I supposed to return. I don't have to think about this other thing or sometimes another thread can go in and change that underneath me.
That combination of having stuff be immutable and only caring about your inputs, I can't imagine going back. I think just how much I can focus on the function at hand, like you mentioned, there is such a difference in how I think about programming now that I would find it hard to go back.
Declutter Your Programming and Learn New Things
Anjana Vakil: I think it's really interesting the way it changes how you approach the act of programming. I totally agree in terms of having to keep less stuff in your head. That's the amazing thing about it. And then there are other consequences as well, for example, when you have these programs that are just framing things in terms of inputs and outputs. And don't really rely on a lot of states, don't rely on a lot of other parts of the program, then things get a lot easier to break apart and scale up. You can put the same function on a bunch of different servers. And it's all running just as fine as opposed to trying to take this big, massive, clunky system that depends on a bunch of other services running, and try and get it to scale up.
Or you can work on those performance issues, like, we said. You can narrow it down to say, "Okay, I have these inputs and these outputs, but I could be doing it a little faster. Let me rewrite this function." So I think, there's a lot of other kinds of practical consequences. But I totally agree that in terms of the day-to-day life of a programmer, it just makes your brain hurt less once you go through the initial pain of the change in thinking that you need to.
I'm personally a big fan of working in as many different paradigms as possible, essentially. Or at least I like to learn a little bit about different paradigms, even if I don't work in them a ton. Personally, I think it's really a fun exercise and a fun way to stretch your brain and give your neurons a bit of a workout to think about different ways of conceiving of programming and of the different types of things you'd need to pay attention to when programming. Learning a little bit about logic programming, let's say, which is another declarative paradigm. Or learning a little bit about how, for example, Erlang and the BEAM work. And the kind of more actor-based or sort of entity-based kind of programming.
I think learning about those different types of thinking about programming can also be really beneficial, even if you don't work in them every day. Then when you go back to your kind of home base language, or paradigm, it can help you really appreciate why it is that you're writing the code in this way, and what benefits you get. And also keep in mind the struggles that you have, when you run up against those points where you really feel like you're bashing your head against the wall, and not getting a lot of traction. It can be useful to have other spaces to go and kind of zoom out and say, "Hey, wait a minute, maybe I'm formulating this problem the wrong way. Maybe in order to do this well, in this paradigm, I need to formulate it in a way that works best for this paradigm."
So I think it's great to switch paradigms from time to time, whether it's just on a hobby project, or going to a conference talk and listening to something new, listening about a different way of doing it. I think it's a really good exercise and makes us all better programmers at the end of the day.
The Adoption of Functional Programming (Concepts)
Lars Jensen: I completely agree. I think it's also one of the things that I see more and more of, cross-pollination between different languages and different communities. One of the things that I was wanting to ask you is also, I see more and more languages adopting functional features. And more and more languages these days, I feel are treating functional programming as a first-class citizen, at least the ones that I've been paying attention to. They all seem inspired by functional programming in one way or another. But functional programming has been around for a long, long time, so why do you think that that is happening now? Or maybe it's been happening before and I just didn't notice?
Anjana Vakil: Since I came from a different background, I haven't been in the computer science world all that long. But my understanding is that functional programming has been around since the '30s. It's been around since Alonzo Church, the Lambda calculus, all of that stuff. But I think it was always really appreciated in the academic world for its beautiful mathematical properties and consistency. And so it was always kind of embraced academically.
But when it comes to working practically with computers and humans and the things humans love to do with computers, you have a problem, right? Because the world has states like humans have ideas that change over time. Humans have bank accounts that they want to change over time. Humans have things that they want to do in the world. And all of those end up being side effects. You can't do anything in a functional language besides return an output. So how do you deal with practical, real-world side effects?
I think the academic languages had been developed to not really have to worry about that problem, and to just show that the kind of mathematical and logical properties were there, and investigate those and kind of advance the thinking there. they, I think, took a few decades, several decades, to figure out, "Okay, is there a way we can then hook this up to the real world, take the side effect-y things that we need to do, wrap them in something functional, which then we can isolate the side effects on sort of the outermost surface of the program, and keep the inner workings of the program all purely functional?"
I think it wasn't until the last maybe 10 or 20 years that really practical functional programming became something that was doable in a mainstream way, that was performant enough to actually write programs in, that had the capabilities that real-world programmers needed. And then, of course, you have a transition period of it starting to trickle out from the academic world, and make its way gradually into kind of everyday programming as it were.
And then other languages, as you say, start to notice, "Hmm, this functional thing, it really does have a lot of benefits. So maybe let's start making it a little easier to do a little bit of functional programming in our environment that we're working in." Whether it be an object-oriented one, or just strictly imperative or procedural one. Being able to make functions first class, let's make it so that you can return a function from another function. And then you can start to build all kinds of stuff with these higher-order functions.
Or let's create anonymous functions, let's add lambdas. And make sure that people don't have to define this whole big, complicated kind of function object or what have you. We do that for them, we just let them write a little, tiny one-liner function to do the things that they want to do. Let's add utility methods like mapping and filtering and reducing and stuff like that.
I think that that process of slow trickle out from the theoretical world where functional programming is this beautiful, elegant system that has all these amazing mathematical properties to become something that you can actually do work in, that just took us a while as a community. And it's still an ongoing process. I think we're still in that trickling out phase.
I'll be curious to see in 10 years and 20 years how much has functional programming taken over? How much have people bought into the benefits, the ease on your mental strain, as it were, and the security and performance and kind of maintainability and predictability guarantees that you get from it? I would not be surprised if we see the needle move even more in the functional direction.
Functional Programming for Everyone?
Lars Jensen: That I agree with you and I think that's where we're headed. Or that's where I hope we're headed. Because for me, at least personally, before I made the transition, so to speak, functional programming was always shrouded in a sense of academia and mystery. I had this impression that "Oh, to do functional programming, I need a Ph.D. in math. And I need to know what a monad is and what a functor is. And I need to know what algebraic data types are.
And it was this ivory tower sort of thing that seems unapproachable. I think that's what I've seen happen with the newer languages. It is that they've just made it more approachable, more friendly and I still don't know what a monad is. I couldn't explain it to you. I still don't know what a functor is, but I'm sure under the hood, I'm probably using them. Does that match your observations or what do you think?
Anjana Vakil: Totally, and I think that was my impression, too. When I first learned that functional programming was a thing, it sounded very scary when I started googling it or, you know, looking it up on DuckDuckGo, as you will. I was overwhelmed by all of the academic jargon. I had somewhat of an academic background so that even for someone who's been used to looking at white papers all day, and reading formulas all day, it's still really dense and not that approachable.
Part of that is that there are some mathematically complex ideas in there. But another part of it that I think we all as a community can decide to overcome is a problem that's a bit more generally pervasive in computer science and in software development, which is this kind of exclusive attitude that folks have had to certain types of knowledge. This kind of gatekeeping of, “I learned this, and I struggled to learn it, and I felt stupid along the way, and I felt not good enough, and I felt insecure.”
Then I finally got to a place where I was able to pass the coding interview and get a job at this place, or I was able to write a Haskell program, or whatever the thing was that I did, and now I feel special. And now I want to keep you from having that same special feeling because I had to suffer and struggle to get it. So I'm going to make it seem as difficult as possible and make you feel as small and as worthless as possible, trying to learn this because that's how I felt when I was learning it. And I am going to keep that going for the next generation, as it were, of programmers.
I think we can do so much better than that, you know. We can think like, "Yes, okay, as a community, we spent decades, a century basically, grappling with these concepts, wrapping our heads around them, struggling to understand what they meant, and how we could use them for practical programming purposes. We struggled as a community, and as individuals we struggled, and we felt stupid, and we had to go through all of this hard work to understand this stuff." But now we understand it and now we can explain it to you. And now we can show you that it's actually really simple in terms of the core ideas that you need to be productive in this paradigm. And that anyone can do it, just like anyone can do programming. Period.
I think we have a wider problem that mirrors that same structure with gatekeeping around programming and this idea that you need to be some kind of genius, some kind of a whiz kid that spends 26 hours a day on your computer or only in the terminal writing everything in cryptic, three-word phrases. I think that we have the same problem in terms of programming, in general, of gatekeeping and trying to keep people out, trying to make people think that you need a Ph.D. to do it, or that, you know, you need to be Bill Gates or somebody, you know, sort of sitting at home in the basement in Seattle somewhere, writing code all the time.
I think it's a bigger problem we can all solve in terms of welcoming new people in and helping people to not have the struggles that we had when we were trying to wrap our heads around this and trying to help them get to the end goal as quickly as possible and as easily as possible. And help give people the confidence to know that, yes, some of these are complex, this will hurt your brain a little bit, but it's doable. You can do it, you can learn these concepts, you can become a productive programmer, you can get a job in this field. You can belong here in the world of functional programming, in the world of programming, in general. I think that's something that we can all decide to do better.
Lars Jensen: I think we can all benefit from having more people join the field with as many different backgrounds as possible.
Anjana Vakil: Absolutely.
Lars Jensen: I don't remember where I heard this, unfortunately, but there was a study done that showed that having a language background, rather than a mathematical background, was a bigger predictor of programming ability down the line. Understanding language was more important than understanding mathematics. And I think that kind of goes against a lot of the conventional thinking around programming for the last many decades.
Anjana Vakil: Interesting. I have heard that about music, for example. Having a background in music theory is really helpful for programming. I've known several programmers that came from the music world. I didn't realize when I was studying philosophy, and I was studying things like formal logic and systems of grammars and things like that, that that was the core of what I needed to become more proficient with programming, it was sort of the logical side of it.
I think there are so many fields where there are directly transferable skills. And again the deeper you get into software development, the more it becomes clear that it's about humans and how humans think and learn and communicate with each other. Understanding some of the psychology behind that, understanding things like language acquisition, ways that people relate to each other, and the types of attention issues that people have and the types of memory issues that people have is very important.
I think there are so many different perspectives that we can take on doing software development that agree that the more people we have doing this stuff, the better the systems will get. And let's be honest, we all have a lot of code that could be way better than it is. We have systems that are running the financial services of the world or the airplanes of the world, we have so much code in our world that can be so much better. And we have all this code that hasn't been written yet to serve the problems and the needs of so much bigger and wider kinds of groups of humanity, of the population, that we need all the programmers we can get from as many different places and backgrounds as possible. So I totally agree, the more programmers, the better.
Lars Jensen: Yes, I would like to agree with that. But also just to backtrack for a second, when you mentioned functional programing becoming more approachable over time. I think that's time to toot the horn of my language of choice a little bit.
I think that one of Elixir's greatest strengths was that they managed to make Erlang approachable because the things that make Elixir great and where the strength is coming from, are the Erlang parts.They're not new things. They just made it more approachable. They added some syntactic sugar and they made sure that the error messages are helpful. They made the onboarding experience for new users much nicer and friendlier.
And I think that's one of the biggest reasons why Elixir has become successful. It's still a small language, a bit of a niche language. It doesn't have the user base that some of the other languages have but I think that was one of their main victories: they made Erlang approachable.
Anjana Vakil: Yes, I've definitely heard that as well. And I think it's amazing to see folks taking really good ideas, and then making them even easier for people to access and use. That is awesome and so great to see. I think some other languages have done this really well, for example, Elm comes to mind. A purely functional front-end language that has just such an amazing kind of dialog with the compiler, the error messages that it gives you, it's almost like you're having a conversation with it. And it's like, "Hey, I think you forgot this thing, or this isn't working. And here's why. And let me point you to something you can read about it."
What I've heard of a lot of beginners coming to languages like Elm, like Elixir is this feeling that you can think of the process of writing code as something where you're fighting with the computer, you're fighting with the compiler to run and to put your code together, or you can think of it as something collaborative, where it's like me, and this language, we are working together to try and solve a problem.
And I think the languages that are making things approachable, are really doubling down on that latter approach of really trying to think of the language as like a pal for the programmer, and not something that the programmer has to struggle against and suffer to make work and understand. I think there are some really great examples out there of this happening.
That's why languages like Scheme were created as a teaching language. Lisp-y teaching language, that can help people just learn the fundamentals of programming happens to be in functional programming, it's great. There are fewer things, concepts to learn in a sense because you really just need functions. And that gets a little bit more complex, of course, but you can start small and build your way up.
And so languages like Clojure, for example, is a really great language. I participated several years back in ClojureBridge, which is this amazing initiative to teach women and non-binary folks how to code for the first time in Clojure. In Clojure there's not a lot of syntax to learn, it's all parentheses. So that's cool. I think functional programming and functional languages can make not just functional programming easier for people to understand and work with, but programming, in general.
It's really awesome to see all of these languages that are intended to be a kind of stepping stone into the vast wide world of all of the computing that take a functional approach because it can be really helpful for beginners, and for folks who are just trying to wrap their heads around a few things that make them productive. And I think functional programming is great for that.
Where to Start?
Lars Jensen: My gut feeling is that if you don't have any preconceived notions of what programming is like, then I imagine approaching a functional language being easier than some of the alternatives. And the only reason why it took me a while to get started was I think that I had some stuff I had to unlearn. I had some habits I had to change and some neural pathways had to be rewired in my brain. But coming in blind, I think can really be easier. It brings me to my last question for you. Do you have any tips for people who want to start with functional programming?
Anjana Vakil: The main thing with functional programming is to not think about the fancy jargon, and all of the monads and functors, and things like that, and not the hardcore impression that people have of some of these languages, like Haskell and whatnot, but to start thinking about what your program is trying to do in terms of data transformation. For me, that was the hardest, and also the most crucial step, I think. To wrap my head around functional programming was not so much memorizing syntax or memorizing what a pure function is. But I'm really starting think about programs in terms of data coming in, and data going out.
And so that's an exercise that we can do without sitting in front of a computer. We don't have to be looking at our code to do that. I think this is something that we can work on when you're trying to reforge those neural pathways or change your way of thinking about it. It’s thinking about, “I'm trying to build this app. I want it to do X, Y, and Z. How can I stop thinking about that in terms of when the world looks this way, and someone does this, this happens? How can I think about it in terms of, here's some input that's coming in, that's all of the crucial data that I need to do some calculation. And here's the output that I'm going to return.”
More so than trying to unlock the mystery of what a monad is, I think it's more important to really think about how you're conceiving the problem that you're trying to solve. If you can teach yourself to think about it in terms of data coming in, and data going out. And how you can link up a lot of that little “data comes into this one and goes out of this one and into this one and out of that one”. How you can link those data transformation problems up to solve your use case of what you're trying to do. For me, that was sort of something that I probably should have practiced more instead of jumping right into trying to learn about a bunch of language features and things like that. I think that was the harder part.
My main tip for anyone learning anything is to find people who are doing it too, to find your community. And to find folks who are also struggling with the same things that you're struggling with. Now as we mentioned it, functional programming has become so popular and so mainstream and has appeared in so many different contexts, including a lot of beginner programming contexts, that it's relatively easy to find folks who are at a similar stage in their learning journey and are working with the same types of technology as you. Whether it's a matter of finding meetups, going to conferences, finding online communities.
For me, it was finding a community called the Recurse Center in New York City which is an amazing programming community of folks who are doing a self-directed learning journey, working on advancing themselves as programmers at whatever stage in their learning they are. This is just this amazing community in New York that I would love for folks to go check out and read about. That for me was a community that really unlocked so much. It taught me what functional programming is and why it's interesting and why it's useful and how to do it.
I think the main tip I would give anyone, and this is not just if you're trying to learn functional programming, but if you're trying to learn programming, object-oriented programming, performance, SRE, whatever it is, find community. Find people, who you can be yourself with, who you can ask questions that you might be nervous to ask, and who can share their learnings with you, and who you can share your learnings with because I think that's also a really amazing learning tool, being able to help somebody else out once you've gone through a struggle.
Like that moment, right after you've struggled and bashed your head against something and finally broken through to understanding. That is the perfect moment to help somebody else out who's one step behind in that process. Yeah, find people, find community, share what you're learning, I think that's the number one thing I would recommend.
Lars Jensen: Thanks for that. I think those are really good tips. I can only agree that the best way of learning is to teach. Just saying things out loud sometimes makes you realize some of the things you were just silently assuming.
Anjana Vakil: Absolutely. This is why I do what I do, essentially. This is why I love teaching. This is why I love going to conferences and giving conference talks and things like that. For me, it is the best way to solidify my own learning. I think it's really great.
It goes back to the point of functional programming becoming more accessible. I'm always reminded of Feynman's quote of "You don't understand a topic or a concept well enough unless you can explain it to a room of freshmen, first-year students in a single semester." If you can't explain it to a beginner or to someone who knows nothing about it, then you don't understand it well enough. And you need to go back and work on your own understanding.
I totally live and die by that. I think that's an amazing way of thinking about things. And I think it's something that the functional programming community could also take to heart. If people are still struggling to understand how to work with these concepts or how they're valuable or what the kind of meaning of various jargon terms is, that means we can all do a better job of communicating it. I think that's something that we, as a collective from beginners to career-long experts can all work on individually. How can we make this easier for someone else to understand? How can I help save somebody else the mental struggle that I went through trying to wrap my head around this?
Lars Jensen: Well, I hope that this conversation achieves that for somebody out there reading.
Anjana Vakil: Yes, and thank you so much for the chat. It's amazing to talk, to catch up and just to have a little bit of nerd out time on all of these great topics. So thank you so much for bringing me on.
Lars Jensen: I want to thank you for taking the time to talk with me. And I hope that I get to see you at a conference in person at some time in the not too far, too distant future.
Anjana Vakil: Absolutely. Definitely, hoping for that and really looking forward to seeing folks in person again and getting to really dig into these exciting philosophical questions of what is programming and how do we do it better, and how do we teach it better? It's just amazing. Really hope to continue the conversation in person sometime soon.
Lars Jensen: Me too. Well, thank you very much.
Anjana Vakil: Thank you.