Functional Futures: Carp with Erik Svedäng

In this month’s episode of Functional Futures, our guest is Erik Svedäng, a game designer who has created many board and video games. Among them is Else Heart.Break(), a puzzle video game with its own programming language. He is also the creator of Carp, a statically-typed lisp for real-time applications.

In the episode, we talk about game design, game development, and how Carp enables developers to build performant games while keeping true to functional programming idioms.

As always, you can check out the episode on our YouTube channel or listen to the audio version on our podcast page.

Highlights from the episode

Game design

Jonn: We invite a lot of programming language designers to our podcast. And we usually jump straight into the goals of their programming language and some specifics of the runtime, etc. But with you, we’ll obviously start with games, because this is, as far as I can tell, your passion. And I think that in the case of Carp, your language, it’s kind of impossible not to start by talking about games. I hear a lot of stuff like “oh, games are so silly” or “why do adult humans play games”. Why are games so important to you?

Erik: Oh, big question. Well, I think most humans actually do play games. Even people who say they never play games actually prefer or like to play some games on their phone, and they like to play games with their friends, and so on. So it seems to me like only very boring, busy people never play games. And it’s just a part of life, I think, to enjoy games, especially with others.

So yeah, for me, it’s just one aspect of a full life. Like, you have to have food, you have to enjoy music, and you have to play some games sometimes.

Jonn: That’s a good description. And when you were talking about it, I thought that maybe even some day-to-day activities that people don’t recognize as games have features of games, where people think about those as games without realizing that those are games.

Erik: Sure, yeah, I think that happens a lot. Like, crossword puzzles or game shows on TV, and so on – that’s a very old-fashioned way of streaming.

Jonn: A very, I think, important thing to consider when we’re kind of thinking and talking about games is – what are the buckets into which we distribute games. And you know, in my humble opinion, I think the way that a particular game designer spreads the games into these buckets informs the games that this designer makes. How do you divide different games, such as, for example, Sims, Dungeons & Dragons, Magic: The Gathering, and others?

Erik: Well, that seems like a long-winded way to get me to define what a game is, which, as an academic of games – that’s a whole complete podcast.

When I create games, I don’t think too much about these pockets. My games have usually fallen into two piles. One is very hardcore versus games, kind of like new versions of chess and Go, but maybe for iPad and for the digital medium. So those are very much like hardcore game mechanics games.

And then, on the other hand, I’ve also worked a fair bit with storytelling in games. And I think those games usually can’t use game mechanics in the same way. It’s hard to force too many game mechanics on that kind of game, where the story is actually what you want to focus on.

So, for example, in Else Heart.Break(), which is one of these story games, despite the puzzles in the programming – if you fail to solve the game or the puzzles, you actually still get to experience a story, it’s just a story about this programmer who is not very good, and it still becomes a fun story. I think, for storytelling, failure is usually a big part of it, stories are about people who have problems. Maybe they succeed in the end, but still, tragedy is a big part of good storytelling.

I think that’s maybe one of the big divides between games: should the game be about winning or about losing. So yeah, I think that’s one way to divide up games.

But on the other hand, there is so much technology and systems thinking, and so on that overlaps between these two things, so you could just as well put them into the same bucket and say that it’s just games or whatever.

Jonn: Does it mean that, for example, when you’re making a, let’s say, computer “versus” game or a board “versus” game, do you think about them in the same way?

Erik: I think I used to think about them completely differently or more differently, but I also feel like the more I’ve played board games and thought about this, I feel like board game and social play, and word play, and all kinds of play can really or could really inform video games in a lot of ways.

I mean, let’s take something like Among Us, which is kind of a social party game converted to a video game, and it got a really big effect out of that. That’s maybe a good example of the kind of thing you can’t really get to – like, it’s obviously inspired by board games, and so on.

The more I learn and think about game design, I’ve realized it’s all the same, actually, in the end. It’s systems that we interact with, and what’s really important is what happens in our head when we play and what we experience, actually.

Jonn: I wonder how many of our viewers and listeners currently think “well, what is game design, even?” Because, on one hand, it’s a very, very old profession, right? We already mentioned chess and Go in passing, but it’s not like people who were inventing chess were professional game designers, right, it was very much an incremental process that spanned perhaps like hundreds or thousands of years. I mean, we have a documented history of chess rules evolving even over the past three centuries or something.

But recently, game design, at least as far as I know it’s fairly recently, has started to be recognized as a proper profession and with research elements to it. So you can go to university to study game design, but I think that there’s still this kind of veil of mystery around it. So if you could lift it a little bit and then talk a little bit about what it means to be a game designer, it would be really nice.

Erik: Sure. I’ve mainly worked as a game designer on my own or with a very small group of friends, so I don’t know much about how it is to be a game designer at a triple-A game studio, actually. It’s probably fun, but it’s very few people who get to command thousands of people to make these huge titles.

But, I mean, usually the game designer is the person who has an idea for what would be a fun game, so they are kind of the person with a vision, a bit like a director for a game, and they try to get this vision through the process of drawing art and programming the game if it’s a video game. And yeah, they’re usually also very much in charge, of course, of testing the game, especially in the early stages, like playtesting with people and seeing what is fun, and they, of course, play the game themselves a lot and change the rules of the game. So yeah, the person who comes up with the rules and the theme, and so on for the game.

Jonn: You mentioned that game designers work a lot on playtesting. So what are the actual further stages in game design before you can, you know, present your black and white prototype or beautiful prototype to your friends and start to test it?

Erik: Well, I mean, the most common place for game ideas to die is when you just try to make it work the first time, I would say. Someone has a great idea in their head and they think about the game, and then, when they sit down and start to try to put it to paper or to code or whatever, it just falls apart and it doesn’t feel as much fun as it felt when you thought about it. Because when you thought about it in your head, it was all alive, in a way, but then you have to make it so concrete when you make it on your own, or actually make it.

So yeah, that’s the first playtest, and it’s not even a playtest, it’s just the first obstacle to get over. But if you can get over that and if you can get through – usually, I try to just simulate the game versus myself to spare anyone the pain of having to play through the game, but if it feels like I actually have to make interesting decisions on my own (let’s say this is a board game), then I’ll bring it to my girlfriend or a friend or something and start playing it, and usually it changes a lot from there.

And then you just keep doing that and making, hopefully, smaller and smaller changes, until it’s something that actually works. And by that point, maybe you have started adding art and so on, and then you’re actually kind of recreating that magic that you had in your head from the beginning. But there is a long stretch there where it’s just not that cool.

But if there was something to your initial idea, I mean, that’s kind of the trick – to have this kind of seed or core vision that you can have to remember that feeling that you wanted to create in people at the beginning. If you can use that to get to the end point where that actually happens, that’s very cool and satisfying, and then you probably have something good by that point.

Game development

Jonn: Approaching the language that you made that is game oriented, can you tell us a little bit about how you approach programming games? Does it mimic the design stages? Do you have a method? Like, you have an idea for a game, you kind of have outlined its rules, let’s say, and what do you do then? Are there certain steps, like, I don’t know, I’ll take Unity, I’ll encode my gameplay loop, etc.?

Erik: Yeah, I mean, I’ve been jumping around a lot when it comes to technology. I guess, Unity is the thing I’ve used the most. A lot of game developers have the same story, it’s like the go-to tool. Creating my own language is, of course, a way to get away from that. My latest project, I used C for that one as a way to not have to use Unity.

But no matter what you do, when you make video games, what you usually want to do is to get something up on the screen. And if there is a game about moving around something, which it often is, you want to be able to move that thing with your controls. And the interesting thing about that is as soon as you have that on the screen, since you made this happen, you usually get stuck for hours.

Anyone who has programmed a game knows this. Like, it could just be a square that you move around with your gamepad, and it’s so much fun to move it around. So yeah, I guess, the professional part of me is like “yeah, yeah, so then don’t do that for five hours” but maybe I do. But yeah, you just want to get to a point where you can start feeling if there is some kind of magic to your idea.

Usually, with video games, there is a lot more extra stuff and reusing of tried and true game mechanics. For example, maybe you are creating a platforming game where you jump, and even if you have a lot of interesting ideas around the jumping part, it’s gonna work, if it doesn’t work, it’s because you did something wrong, it’s not like this is a broken way to control a character.

While if you create your own kind of game system from scratch for a board game, it could very well be that it’s not working at all. So it’s a bit different in that sense. But yeah, you just want to get to the unknowns quickly to see if you can get those working, and if your programming skills are good enough to make it happen, whatever it is that you want to happen.

Carp

Jonn: Basically, as far as I understand, you’re kind of going through the boring parts, and then you get to this open-ended thing where you actually code your game, and then, you know, you hope that you don’t crumble under like technical debt, third-party dependencies, and stuff like this. Where does Carp come into this? From what I understand from our interview so far, you kind of created it out of frustration with state of the art, one could say. Is it fair?

Erik: Sure. I’ve spent a lot of time, basically the last 10 years or so, trying to come up with a way to write games using functional languages. I did a lot of research on programming languages when I was making the language for Else Heart.Break(), and that got me, of course, into a lot of theory and books, and information about all these functional languages, and they really spoke to me, especially Lisp and Haskell.

And at the time Clojure was kind of newish, and I learned a lot of Clojure, and that was my favorite language for a while. And I really wanted to make games with it. It felt like the perfect system for creating games, with the live reload and all of that, but I realized that it had a lot of problems for making a sizable game.

I mean, Else Heart.Break() is not super optimized, but to create something of that size in Clojure, it would kill the computer, it would die, probably. It’s just really hard to handle the kind of data throughput and garbage collector nonsense that you have to deal with in that kind of language. But at the same time, I, like many people, had seen the light, I had seen how nice these kinds of languages could be and it just felt really boring to go back to writing games in C# and just be fine with that.

So that’s when I started thinking about if I could make a kind of a Lisp that I could actually use for my future games. That was the vision and goal, which I’m still working towards. I have not yet made an actual finished game with Carp, so it’s still just a distant goal but one that I’m still working towards.

Jonn: Do you have some demos of squares moving around out there already?

Erik: Sure, I mean, I’ve made Game Jam games and so on with it, but I realized that to create a big game with it, it would have to be even more stable and even faster as a compiler. Like, I can’t spend years working on something and then get stuck because my language is not good enough. Even though I think the runtime characteristics of the language would be fine for most things I want to do. But there is also just the whole tooling and especially compilation speed, which becomes a big factor when you make an actual big game or big project.

So that’s where I’m right now with the project. I’m taking a very good look at how to create a new version of Carp that has much better compilation speed.

Jonn: And the main features of Carp, aside from it being a Lisp, are that it’s borrow-checked and well-typed, right?

Erik: Yeah, exactly. The type system is kind of an ML, very basic, standard, sum types, product types, that kind of stuff. And yeah, it’s using borrow checking, very Rust-inspired but still has a kind of different feel from Rust, it’s not trying to be as detailed as Rust, it’s trying to be a bit slower but more ergonomic.

Rust is obviously a very huge influence for a lot of programming language designers nowadays, and especially people who want to make languages for games and so on. And yeah, I think it’s just kind of interesting – Rust has made their decisions, but there are many little choices you can make different from them. And I think it’s cool to see different languages trying out variations on the core idea of a fine type system.

So yeah, it feels like Rust really started a kind of revolution there with lots of languages experimenting with those ideas.

Jonn: Do I understand correctly that the biggest problem, for example, with using Clojure for programming games would be that you have a lot of stuff going on all the time and since it has a garbage collector, you kind of want to make sure that you don’t hiccup between the frames, or something like that? But how does Unity solve it? Do they have some sort of a custom runtime or is NET just so much better?

Erik: I mean there are many factors there. Unity is written in C++, I think, like the core, so it’s actually not C# all the way. That’s just in the user space. So that’s one answer. The other big answer, of course, is mutability. Like, it’s really relying on mutability, so if you just have a thousand objects in the scene and you move them slightly, you actually create no garbage at all, while if you do that in Clojure, for each frame you would create garbage for basically the whole world each frame, which is a big difference. And yeah, I guess those are the main differences, then also C# and .NET is very good for some kinds of memory usages, but so is JVM, of course.

But yeah, I think with all those things together, you get a pretty nice system. But people still run into problems with the garbage collector in Unity, so it just becomes a problem later in production. Like, you can get away with it for a long time, but if you don’t think about it, eventually you’ll have to start thinking about it, and at that point it’s not very fun.

Carp tries to be more upfront about that whole thing. Like, you would have to think about memory in the beginning of your project, but not that much in the end, while C# is the other way around.

Jonn: That’s very interesting. I assume you actually have a way to store mutable state of the world in Carp?

Erik: Yeah, it’s actually completely free in that sense, exactly like Rust, you can mutate anywhere. It’s not like Haskell where you have to mark things at all. If some algorithm or function would benefit from some kind of mutability, you can just do that wherever you are.

But the main tools people should reach for when they write a program in Carp are supposed to be functional in nature, so there are maps and filters, and so on, and those are supposed to be how you do the bulk of the work, but you can always go in and mutate if you want to. At least in the current design.

Jonn: Let’s say I want to make a very big tic-tac-toe or a Game of Life, something that can be unbounded, that can grow. How would you do that in Carp?

Erik: The way I prefer to do it is to write it very much like you would write in Clojure with immutability (like, it looks immutable). So you would maybe have some kind of reduction over the state over time. So you’re actually not storing the state like in a mutable variable or something, you’re just passing it around and around in a recursive function, basically, from the outside. And all your functions look immutable – they take the state and return the state, but since they have the borrow checker rules ingrained in them, they can do internal mutation if that’s faster. And they know that no one else is sharing that state, so it’s completely safe to do so.

Usually, that’s the kind of code I’ve been trying to make work. You basically take something that would run in Clojure and you run it in Carp instead, and instead of getting killed by GC, it never allocates after the first frame, basically.

Jonn: By the way, when I asked you how do you develop a game and you said “well, you want to get something on the screen as soon as possible” – with Carp, I can attest that it’s like really, really quick. It’s almost like I remembered in school when we had the Pascal language and you had like a graph module, you could write like use graph and draw straight away.

Erik: Yeah. I guess most languages could be like that. I just ship the compiler with some graphics bindings to STL. It’s not important that it’s STL, it’s just like it feels good for this kind of project and this kind of language to have something out of the box. It’s not the only thing you can use, but it’s something that everyone will have access to, so if you want to do something quickly or you want to do a tool or something, you know it’s built-in and it’s there. I think that makes a big difference compared to most other languages where you have to go to the package manager and find those bindings.

I mean, maybe in the future we’ll have to remove it, but I think that has been very good for people to just try out the examples and try out the language. Because it’s supposed to be used for that kind of stuff, it’s good to have it built in. I’m happy you had this experience, that was exactly what I wanted: like, just download the compiler and paste in some simple example code, and actually get graphics on the screen, and not just text.

Jonn: What does Carp compile to?

Erik: Right now, it compiles to C. The compiler is written in Haskell and compiles or emits C code, and then you use some C compiler on your system to compile it. In my new secret version of the compiler, which is going to be much faster, it’s using LLVM straight up instead of C.

And if I get that to work out, it’s gonna be much much faster. Since it’s a Lisp, it does a lot of cool stuff with the dynamic runtime to get the language to work, but that is also hard to get fast enough in Haskell. At least for me, it’s hard to write a very efficient interpreter. So the idea there is to use LLVM editing to get a much faster dynamic runtime so that compilation is faster.

Jonn: How do you see Carp used in the ideal world? Let’s say you have infinite resources. Like, you can hire the best engineers from Facebook to work on Carp. How would you develop it, and to what goal – how would engineers use the ideal Carp?

Erik: Well, I just want to have a decently fast compiler that handles what the language is right now. If you download the compiler right now, it’s a bit buggy but it works. And so I think that system would suit me very well, just no bugs and decently fast compile times is all I’m really asking for.

My idea was to make it pretty small and easy to learn language, so it’s not supposed to have that much more. The cool thing when you have macros and so on is that you can create so much yourself if something is missing, and that’s been really fun – to see people. For example, one of the coolest things that the community did with the language was to create a derive functionality, which the language did not have, where you could derive different interfaces for types, and that was just all built with macros.

Yeah, it doesn’t need to be much more than what it is right now, it just has to be done in a more efficient way. And I think now we have learned a lot from creating this current version of the compiler, so I think a rewrite of sorts will be pretty beneficial, in that sense. Since we know so much more about how to create this kind of language.

But yeah, I don’t need all Facebook engineers to make this happen, it shouldn’t be like the biggest project ever, I think. And I mean, when it comes to reaching out, I think, there is this very particular kind of person who likes both Lisp and game development. There is definitely a crew of people who enjoy both of these things, but it’s never going to be the mainstream. It’s like a niche thing.

But I think it would be fun if people in that niche got to try it out, and that it worked very well, and they could use it for their projects. So yeah, just trying to fill the needs of the gamedev Lisp programmer, that’s my only goal.


Thanks to Erik for being a guest on our podcast! 🙏

If you would like to learn more about Erik and his work, you can visit his website. To learn about Carp, you can visit its GitHub page.

If you want to hear more from us, be sure to subscribe to Functional Futures either on YouTube or your favorite podcasting platform.

Functional Futures: Carp with Erik Svedäng
Haskell courses by Serokell
More from Serokell
Lorentz: Achieving Correctness with Haskell NewtypesLorentz: Achieving Correctness with Haskell Newtypes
interview with Chordifyinterview with Chordify
Optimizing K FrameworkOptimizing K Framework