What kind of software is functional programming not suited for?

Functional programming cannot be suited for everything, right? Well, let's not be so sure. Functional programming, like imperative programming and object-oriented programming, is a paradigm. It is a fundamental way to approach software. There are many languages that fall within the umbrella of FP. It is quite possible that everything we know how to do in software, we know how to do well with FP, the same way we know how to do it with imperative and with OOP.

Transcript

Eric Normand: What kind of software is functional programming not suited for? We will go over this question and explore it in some depth by the end of the episode. Hi, my name is Eric Normand, and I help people thrive with functional programming.

This is an important question, because if we are being honest with ourselves, we're going to find places where something isn't a good fit. If it's a good fit for one thing, there's going to be a bad fit somewhere else. To say that a thing is good at everything is probably to delude yourself.

I want you, my listener, to have a more balanced view of what's going on, so we're going to explore this question. I'm going to make reference to other paradigms, object-oriented paradigm and imperative paradigm, and we'll see. We'll see how they all do as paradigms.

The question is, what kind of software, what applications, what domains, what kind of context is functional programming not suited for? My first impression is this is like asking what object-oriented programming is not suited for, or what imperative programming is not suited for.

Even though I don't generally endorse imperative programming, like in the same way I endorse functional programming, it's hard for me to think of a domain where imperative programming is not great. I don't feel like I'm being biased by saying that I think that there's something wrong with the question. I want to go into why that might be.

The thing is, these are general approaches. These paradigms are general-purpose approaches to software. They are more like a world view from which to begin your exploration of a problem domain and how you might solve it. It's not like they're mutually exclusive.

Their ideas certainly aren't mutually exclusive. They just kind of set a groundwork, a framework, in which you're going to continue exploring.

They're a whole system of thinking, and so it's hard to say that some kind of application wouldn't do well in imperative programming. It's a system of thinking. It's a place to start. Likewise with object-oriented programming. It's a place to start.

Just to be super clear, when I'm talking about the three major paradigms, object-oriented, imperative, and functional, I'll quickly give a nutshell description of these as paradigms.

Imperative programming turns everything into a sequence of steps. That is your main programming unit is a routine or a subroutine. You can break up a sequence of steps into further steps, call those and name them, and refer to them that way. You could see that this is a generally applicable paradigm.

A lot of people say, "Functional is really good with math." A lot of high-performance math routine software, is written in an imperative style. It's written in Fortran, so it's really hard to make that argument that functional programming is better at math than Fortran.

Object-oriented programming, there's basically three main concepts. There are objects, which hold state and accept messages, there are the messages that are sent between objects, and there are the methods, which are the code that runs when the message is received.

In this way, you create this network of objects that communicate with each other. The computation happens through the dispatch of different messages and what each object does with the messages it receives.

Likewise, you look at software written today, a lot of it is written in object-oriented programming, in an object-oriented style. It spans all sorts of domains, all over the spectrum. It's really hard to say that it's not suitable for this stuff.

People have built systems to do aircraft engineering, to embedded systems, to simple web applications. Everything is built in this OO framework.

I'm going to say the same for FP, that there's really nothing that FP isn't suited for. Real quick, functional programming as a paradigm begins with three things, the three main concepts — actions, calculations, and data. These are mutually exclusive categories that everything falls into.

When I read answers on the Internet, one thing that I see come up a lot as a good answer or as common answer — and people like this answer, they upvote it and stuff — is that anything that's main purpose or the main function of the software is to keep track of and change state.

They give the examples of stuff like a game engine, where characters and other items are constantly changing. They're moving. Their health points are changing. There's a lot of state, and it doesn't make sense to do this in functional programming, because it's much easier to just set mutable fields on objects.

I want to address this, because it is a very common answer. Functional programmers do use state. Let me just put it bluntly. We do. There is a particular definition of functional programming that I don't agree with that says that functional programming is exclusively programming with pure functions.

That means no state, no side effects, nothing, just pure functions. If that is the case, if it is programming with pure functions, then these answers are right. The trouble is that that is not what most functional programmers do in their day job.

When they're actually building a real system, they are making practical compromises. They are not sticking to this very rigid reductionist definition of functional programming.

That would be like saying in Java, you could only do stuff with message passing, meaning no if statements, no for loops, no primitives. Everything has to be an object. Nobody does that. It's just not the way it's done.

Now, there are some languages that make it easier to do that, like I believe with Smalltalk, everything, even if statements were done with messages. That was a choice they made, just like Haskell makes a choice to be a very pure language, although it does have I/O. Don't forget about that.

I don't agree with that definition. Functional programmers do use state. They do use side effects. They just have a tidy place to put them. They put them in the actions category. All that is to say that functional programming is big.

There's a lot of room in this umbrella of functional programming to solve any problem you might have. That's why it's not really possible to say, "Well, it's not good at this," because it's a big umbrella. That thing fits under there, and someone may have found a way to do it. There's lots of languages.

I'm going to name two domains that maybe I would feel like just intuitively, "Oh, these things, these domains, no. They're not good for functional programming," but then I researched them, and it turns out that there are functional programming solutions in there.

The first one is embedded systems. I looked into this, because I figured embedded systems are super constrained in terms of memory and CPU processing. You're not going to be able to fit a garbage collector in the kind of runtime that we're used to when we're dealing with nice functional languages. But, I was wrong.

There are several versions of Scheme, or other Lisps, that are made to run in an embedded environment. They're pared down. They're not the Scheme you would run on your desktop or on a server. They're very small, and they encourage a lot of functional programming practices, and they discourage others.

There's going to be mutable data, like the const cells, the things you make linked lists out of — they're mutable — but it encourages recursion. It has first-class functions. You make a tradeoff there for space. Now, there's other languages, too. I'm just picking on Scheme, but there's other functional languages.

Then you get to something like Rust. Rust is a very functional language. A lot of it falls under the functional umbrella.

It has a really nice type system that can optimize away a lot of stuff that we've relied on runtimes for in the past — memory safety, being able to efficiently store and deal with mutable state in a safe way.

Rust is a perfect example of functional programming for embedded systems. It's just, it proves that [laughs] it is suitable for everything.

There might not be a language for that particular problem yet, but it doesn't mean that FP isn't good for it. It doesn't mean that all languages are. I would never use Clojure in an embedded system. It's too big. Everyone knows that. No one's going to dispute that.

The other one is the GPU. There are many systems for writing the language that GPUs speak, which is OpenCL, something like that. Oh, I forgot the name. Let me look it up real quick. Yeah, there's Cuda and OpenCL.

These are C-like languages. They're imperative. Like in Clojure, there's ways of writing what looks like Clojure, that gets compiled into OpenCL, and then sent to the GPU. That's not what I'm talking about. I'm talking about a functional paradigm approach to programming the GPU.

I didn't know that this existed, but it does. I would have said, "No, you just want imperative. Just give me the raw code, and let me do it by hand." No, there's a thing called Futhark, F-U-T-H-A-R-K, that is a functional language that operates on arrays.

It has map, filter, reduce, and it happens all in parallel on the GPUs. It compiles to OpenCL or Cuda, and it is a completely pure, type-safe functional language that is competitive with hand-optimized code. It's high level in the way that an imperative language wouldn't be.

To me, this is it. It's saying, "Yeah, sure, maybe Clojure or Haskell itself won't compile right to the GPU, but here is a small functional language that will compile nicely to the GPU." That's what it's made for. It's made for interop with a regular language, like a CPU-bound language.

You're running it in Python, and then you need to call out to something fast on the GPU. You could write it in this nice functional language in a functional style.

I'm going to conclude. I think that FP is generally applicable, because it really is just a general approach to software.

In the same way that object-oriented programming is probably OK, I don't know if OOP would be good on the GPU. Just saying, just because the message passing might...I don't know. I'm not a GPU person, but it just seems like the message passing would be not a good fit for the architecture of the GPU.

That's not to say that it's not possible. I don't know. The thing is, when we talk about whether it's a good fit for a certain environment or application domain, we're usually thinking about a particular language that we are thinking about.

We're saying, "Is Haskell good for this?" OK, Haskell is not good for everything. Clojure is not good for everything. There are particular domains where it is a good fit and not, but FP encompasses all of them. As a framework, as a paradigm, it is flexible, it can do it all, and I think that's the case with imperative and with object-oriented.

Well, yep, that's all I have to say. I hope I've brought some clarity to this. A lot of the fine points are on the definition of FP as a paradigm. I think that state and side effects are a part of FP, just the fact that we have names for them in a way that other paradigms don't. That's it. I'm done.

If you liked this episode, you can find all the past episodes at lispcast.com/podcast. There you can find audio, video, and text of all of the past episodes. You'll also find links to subscribe to the podcast and to find me on social media, be it email, Twitter, or LinkedIn.

I really think the social part of social media is the main thing. It's not a broadcast medium, it's a way of getting in touch with more people, keeping in touch with people, engaging with them, forming relationships, friendships, nice, deep discussions.

Please find me and send me a message and that's it. Thanks for listening and rock on.