In short
Simon Peyton Jones (Haskell co-creator) argues that software insecurity stems from “unsafe languages,” and that statically typed, mostly pure functional programming improves safety, maintainability, and reasoning. He also discusses functional programming concepts (values vs mutation, laziness vs strictness, monads/effect systems), the history of functional language execution models (lambda calculus, SKI combinators, dataflow hardware), and why “functional hardware” didn’t win.
Guest
Simon Peyton Jones, co-creator of Haskell; researcher focused on functional programming’s practical obstacles; known for work on GHC and type-driven refactoring.
Key claims
- Internet insecurity is largely due to unsafe low-level languages; rewriting infrastructure in Rust (or safer functional languages like OCaml/ML/Haskell) would remove ~99% of buffer/pointer exploit classes.
- Functional programming is “programming with values instead of mutation,” making coupling visible and improving modularity.
- Type systems reject “silly programs” at compile time; maintainability comes from type-guided refactoring (e.g., changing types in GHC and letting errors propagate).
- Monads keep purity while sequencing effects via types (e.g., IO t).
- Functional “hardware” (SKI/dataflow machines) was an inspiring mistake because it duplicated runtime interpretation that compilers can do at compile time.
Notable examples
- Haskell’s unsafe perform IO as an explicit escape hatch.
- C: mutation + pointers => “super unsafe.”
- Haskell v1: no IO (string -> string only); IO added via monads.
- Laziness enabling modular generation/pruning (infinite chess move trees).
- Parallelism: Haskell/GHC supports programmer-directed parallelism (e.g., E1 par E2).
Written by AI. May contain mistakes. Listen to the episode to check what was said.
Chapters
Tap a time to open that second in VOUnderstanding Functional Programming
0:45 to 2:15
Exploration of what functional programming is and its significance compared to imperative languages.
“I wanted to start by asking you what is functional programming in your words and why does it matter to people who might use the other languages, the imperative languages?”
The Nature of Computation
2:15 to 4:30
Discussion on how computation works in functional versus imperative programming, including examples from mathematics.
“So it was a surprise to me when I learnt that, well, it is possible to do useful things with functional programs.”
Historical Insights on Programming
4:30 to 7:30
Insights into the history of programming languages, focusing on Turing and lambda calculus as different models of computation.
“And then the question is, what are the practical obstacles?”
Advantages of Functional Programming
7:30 to 9:30
Advantages of using functional programming, including modularity and reasoning about code without side effects.
“But I'm not going to say that they're wrong to do that, just to say that I think there's a pretty interesting dialogue.”
Challenges in Functional Programming
9:30 to 11:15
Exploration of the downsides of functional programming, including practical challenges of side effects.
“But, well, in a pure functional language, the time of day...”
Innovative Hardware for Functional Languages
11:15 to 13:00
Discussion on the potential for designing hardware specifically for functional programming and historical attempts.
“Do you have any idea what that might look like and some high-level thoughts?”
Understanding SK Combinators
13:00 to 14:00
Introduction to SK combinators and their significance in functional programming as a low-level representation.
“thinking oh crumbs what would a piece of hardware look like that could was primarily designed to execute functional programs.”
Understanding the SKI Machine and Combinators
14:00 to 16:44
Learn about the SKI machine and how SK combinators execute programs.
“Thomas Clark, Joe Stoy and others built something called the SKI machine SCIM.”
Runtime vs Compile Time in Functional Programming
16:44 to 19:12
Explore the pitfalls of executing functional programming at runtime instead of compile time.
“Imagine an interpreter for, I don't know, Pascal or something.”
Challenges of Fine-Grained Parallel Computation
19:12 to 21:41
Discover the difficulties associated with fine-grained parallel computation in functional programming.
“I would have thought there might be some unique opportunities for parallelism, given the immutability in these functional programming languages.”
Show all 35 chapters
The Safety vs. Usefulness of Programming Languages
21:41 to 24:25
Examine the trade-offs between safety and usefulness in programming languages, particularly Haskell and C.
“I was searching on YouTube, and I've searched your name, and this video came up, and it said, Haskell is useless, Simon Fayton-Jones.”
Evolution of Haskell's Usefulness and Safety
24:25 to 28:00
Understand how Haskell has evolved from being very safe but less useful to becoming more useful while maintaining safety.
“Like if I wrote something in Haskell, I mean, there's got to be some new type of...”
Comparing Haskell and OCaml
28:00 to 31:45
Learn the key differences and similarities between Haskell and OCaml in functional programming.
“So from Haskell, we're moving sort of vertically to get more and more useful without stopping being safe.”
The Benefits of Laziness in Programming
31:45 to 33:49
Understand the advantages of lazy evaluation in programming, particularly in Haskell.
“And as a programmer, my initial thought is I would like to control the order of execution.”
Understanding Monads in Haskell
33:49 to 35:35
Discover the concept of monads in Haskell and how they manage side effects.
“Strict evaluation forces you to merge them together.”
Purity and Effects in Haskell
35:35 to 41:28
Explore how Haskell preserves purity while managing effects through its type system.
“What is a monad, and how does it help us do side effects and preserve ordering?”
The Trade-offs of Haskell's Approach
41:28 to 42:00
Learn about the trade-offs Haskell makes in specifying sequence and managing effects.
“And because you have to thread, because the type system gets in your face, you were trying to, like map, say.”
Exploring Haskell's I/O and Monads
42:00 to 43:32
Learn about Haskell's handling of I/O operations and the role of monads.
“You want something that says, take a list of I.O.”
Understanding Type Systems
44:10 to 47:34
Gain insights into the purpose and functionality of type systems in programming.
“And I appreciate them for supporting my work and sponsoring this podcast.”
The Importance of Static Type Systems
47:34 to 51:00
Explore the benefits of static type systems, including maintainability and designability.
“So there's an idea that was born in functional programming and made its way into the mainstream.”
Weak vs. Strong Type Systems
51:00 to 56:00
Discuss the advantages and disadvantages of weak and strong type systems in programming.
“What they do is, it's an immutable piece of software, and you do that stuff around the edges to impedance match what you really want to do to this now immutable blob.”
Static vs Dynamic Typing in Haskell
56:00 to 57:29
Explore the benefits and trade-offs of static and dynamic typing in Haskell.
“is that they don't even have the same representation, which is just nonsense.”
Understanding the GHC Compiler
57:31 to 1:01:08
Learn about the high-level workings of the GHC compiler and its design choices.
“So GHC takes a string, like any other compiler, the source code of the program, parses it.”
Type Checking and Compiler Bugs
1:01:09 to 1:03:24
Discover the importance of type checking in GHC and how it prevents bugs.
“You would like to have, as it were, like a generic architecture, one that can do addition and has a program counter and a stack and so forth.”
Cultural Insights of Haskell
1:03:25 to 1:06:56
Understand Haskell's user community and its principled approach to language design.
“So I'm very proud of the fact that core is statically typed.”
Philosophy of Haskell Development
1:06:57 to 1:10:01
Delve into the philosophy behind Haskell's development and its impact on users.
“I thought that was very unique about Haskell because I feel a lot of the other programming languages are user-centric.”
Challenges of Software Compatibility
1:10:01 to 1:12:08
Learn about the difficulties in maintaining backward compatibility in software.
“And that's saying, that's a little joke, but it says if you're too successful and have too many users, it becomes more difficult to make changes.”
The Rise of LLMs and Programming Language Design
1:12:09 to 1:14:09
Discover how large language models are influencing the design of programming languages.
“So I think that statically typed languages are a huge boon for LLMs because it's too easy to get.”
Exploring New Language Design: Verse
1:14:10 to 1:15:57
Explore the unique features and potential of the functional logic language Verse.
“Well, I think another way to tackle is to say, what are interesting, you know, new languages out there that are exploring very different parts of the design space?”
The Importance of Learning Programming Today
1:15:58 to 1:18:46
Understand the necessity of programming skills in the age of AI and automation.
“Yeah, I think a lot of people, like students, they may be worried about AI or studying computer science.”
Fundamentals of Computing for Everyone
1:18:47 to 1:20:49
Discuss the essential knowledge of computing and programming every person should have.
“So I really want long-lived maintainable code to be well reviewed.”
Excel as a Programming Language
1:20:50 to 1:24:00
Learn why Excel is considered the most widely used functional programming language and its evolution.
“I want them to know that computers fundamentally execute by following machine instructions blindly, right?”
Enhancing Excel with Functional Programming
1:24:00 to 1:25:15
Learn how functional programming concepts, like Lambda, enhance Excel's capabilities.
“Answer, take ideas from functional programming and use them to make Excel's formula language more powerful.”
Advice for New Graduates
1:25:15 to 1:26:36
Discover valuable life advice for recent graduates from a successful professional.
“They are, all of them, just making it up as they go along.”
Closing Thoughts and Gratitude
1:26:36 to 1:26:53
Hear final thoughts and gratitude expressed at the end of the episode.
Transcript
Automatic transcript. May contain errors.0:00Simon Jones:Why is the internet so insecure? Primarily because all of our software infrastructure is written in unsafe languages.
0:06Simon Peyton Jones:This is Simon Peyton Jones, co-creator of the functional programming language Haskell, and I asked them all about programming language design.
0:13Simon Jones:If we rewrote all of our software infrastructure in Rust, things would be way, way better. I think that statically typed languages are a huge boon for LLMs. I do large-scale, systematic refactorings fearlessly because the type system keeps me safe. in fact. Would you recommend people learn how to program today? I think people are right to be worried in the sense that I think there's going to be considerable dislocation. Here's the full episode.
0:45Simon Peyton Jones:I wanted to start by asking you what is functional programming in your words and why does it matter to people who might use the other languages, the imperative languages?
0:57Simon Jones:Functional programming is about programming with values instead of mutation. So in a conventional imperative programming, computation proceeds by, like if I want to add up the numbers between one and a hundred, I have a mutable cell containing a running total. And then as computation proceeds, I keep adding, you know, I keep adding to my running total. So there's a cell that changes its value over time. Computation proceeds step by step, there's a program counter. Now, that's very unlike mathematics. If I say 3 plus 4 times 7, you don't think of a mutable cell that changes its value over time.
1:32Simon Jones:You think, well, 3 plus 4 is 7. 7 times 7 is 49. Just the answer is 49. So in a sense, it's more declarative than imperative. Another way to think of it is it's more like what a spreadsheet does. In a spreadsheet formula, if you put in a cell, you'd say in A1, you put the formula equals A2 times A3 plus 7. Well, then that's just the formula that is evaluated. And you expect to compute the values of A2 and A3 automatically before computing A1. It wouldn't make any sense to compute A1 from the old values of A2 and A3. And there's no notion of a program counter. There's no notion of do this and then do that.
2:13Simon Jones:it wouldn't be sensible to say equals print x plus three because who knows when or even whether that cell will ever that formula will ever be evaluated now the surprise is that it is possible to do useful things in such a limited language when i would learn programming i learned it by writing machine code in which the fundamental mode of computation is registers and program counters and mutation of registers as you go along and memory, like computation and mutation seem to be inextricably interwoven. That's how computation gets done. So it was a surprise to me when I learnt that, well, it is possible to do useful things with functional programs.
2:56Simon Jones:I still remember that amazing revelation. Now, in fact, one way to look at it is this. Right back in the late 1920s, early 1930s, Alan Turing was doing a PhD in Princeton under the supervision of Alonzo Church. Now, Alan Turing, as we all know, invented the Turing machine, which is fundamentally about mutation. It has a little tape and you can read things from the tape and then you write back new things onto the tape and it has an immutable program. Now, Alonzo Church, at the very same time, was working on something he called the lambda calculus, in which there's no motion imputation. The lambda calculus is like the essence of functional programming.
3:42Simon Jones:Programs execute just by reduction. Now, so these were two different models of computation. You might ask, what can you compute with a Turing machine and what can you compute with a lambda term? And the astonishing thing that turned out, which is completely non-obvious, is that anything you compute with a lambda term, you can compute with a Turing machine, and anything you compute with a Turing machine, you can compute with lambda calculus. So that means that the two are identical from the point of view of their computational power. Big surprise to me. Okay, so they're equally powerful. And then the question is, which might you want to choose?
4:20Simon Jones:As I say, I started life from my baseline of imperative programming. Of course, that's the way you write programs. And functional programming is a kind of weird, anomalous, rather nerdy academic thing. but I became hooked on the idea that by excluding side effects by default, that is, imperative programming has side effects by default, by excluding side effects by default, we could make programs that are easier to write, easier to maintain, easier to reason about. And then the question is, what are the practical obstacles? Is it slower? Is it less convenient? And so forth. So in effect, I've devoted my research life to exploring that hypothesis.
4:59Simon Jones:the wonderful thing about being a researcher is you can take something which at the time this is back in 1980 back in 1980 a functional program was very nerdy geeky academic but I was allowed to spend my professional life just saying what would happen if you took that one idea programming with values and just ran with it where would you get and I think we've got somebody somewhere pretty interesting. I don't want to say that it's better fundamentally, because after all, Haskell, on that journey, started with functional programming, then we learned how to mix functional imperative programming together in a way that we might talk about later, right?
5:40Simon Jones:So it's not really an either or, it's more of a both and in the end. But my position now is, as I often say, when the limestone of imperative programming is worn away, the granite of functional programming will be revealed underneath. And why do you say that? Well, functional programming is the language of mathematics. That's how we fundamentally think about things when we want to be formal. Indeed, if we want to reason about and say, what does this imperative program do? We have to wheel out a lot of mathematics and, you know, whore triples and so forth. But that's all in the world of maths, which is just functional programming.
6:17Simon Jones:Functional programming is just mathematics brought to life and made executable. So you might wonder, I suppose you may be saying, well, isn't imperative programming just enough? And I think that there you have to look at the broad sweep of things. I think what's happened is that from the world of functional programming, lots of ideas have got adopted into the imperative arena. So they grew up over here in functional programming. And then they have been adopted by the imperative programming. So you might think garbage collection. You might think lambdas. You might think language integrated query.
6:59Simon Jones:You might think about lots about type systems, polymorphism and static typing, tons of that. So at least it has been an intellectually interesting experiment that has been a very fertile laboratory in which to grow up ideas that can infect the mainstream. Now, my instinct now is that we should start from functional programming and do imperative programming where necessary. I think probably the mainstream is we should start with imperative programming and sort of add bits of functional programming where possible. But I'm not going to say that they're wrong to do that, just to say that I think there's a pretty interesting dialogue.
7:38Simon Jones:Now, you do have to think very differently about the act of programming, right? You do have to rewire your brain quite a bit. But just let me, this is something we might want to come back to. I said easier to maintain. As programs get old, think of a 10-year-old program. If you have a piece of 10-year-old code written by somebody who's long since left your company that mutates some more or less global variables, then you might be a little bit afraid about, oh, and there's other bits of code scattered about that also read or write those global variables. then you might be a little cautious about making modifications, right?
8:16Simon Jones:Lest, oh, if I put these two things, if I do B and then A instead of A and then B, maybe, you know, the global variable that I read somewhere deep inside the code is now not have the value that it was expected to. So reading and writing shared variables that are visible, you know, outside the scope, sort of somewhat global variables, is a form of coupling between bits of code that is very invisible. Very invisible. So functional programming forces that to become visible. It forces it into the open. And by the act of forcing it into the open, that strongly encourages a style of programming which you don't have such interactions because they are painful to manage.
8:59Simon Jones:So it encourages a style in which programs execute in modular box without interacting. Now, every imperative programmer would want to do that, But I want them to do that in a provably secure way so you can know that these programs don't interact rather than just say, I've done my best.
9:18Simon Peyton Jones:Then I guess on the flip side then, what are the downsides of functional programming language?
9:25Simon Jones:Oh, well, it can be very task and inconvenient, right? So you're somewhere deep in the subroutine of a subroutine of a subroutine of a software stack, and you want to reach out and, I don't know, grab the time of day. Oh, dear. That's a side effect. But, well, in a pure functional language, the time of day... And, indeed, there's a good reason, because everybody else in Ohio in the stack is assuming that if I call this function applied to, you know, 7, it will give me the same answer if I call it again applied to 7. But if it could interrogate the time of day, suddenly it might give a different answer.
10:00Right?
10:00Simon Jones:So as simple a thing as asking for the time of day invalidates a whole set of assumptions, And so it's not by default allowed at all. And that can be a convenient because you always say, look, guys, all I want to do is get hold of the time of day. Don't give me grief. And so every functional programming language, including Haskell, provides you with a little trap tool. Haskell's is called unsafe perform IO. And it says, trust me, I'm going to do something that has side effects, but you can pretend there weren't any. All right. So, and it's called, it is literally spelt UNSAFE PerformIO, the long name that has unsafe in the title so that you, the programmer, are taking on the obligation to make sure that what you're doing is okay.
10:46Simon Jones:Whereas in imperative language, everything you do could be unsafe before my wish.
10:52Simon Peyton Jones:I was watching one of your lectures and you did go over a little bit the history of functional programming languages. And you mentioned somewhere that there was this idea of people building hardware for functional programming languages. It just made me curious because I only know the von Neumann architecture. Do you have any idea what that might look like and some high-level thoughts?
11:20Simon Jones:Well, I did. I now think it's probably a bad idea. But back in 19... When was Bacchus's Turing Award lecture? I think it was 1978 or thereabout. What was it called? Can Programming Be Liberated from the Von Neumann Style? That's it. Now, he was saying two things. Firstly, he, the designer of Fortran, a quintessentially imperative language, the designer of Fortran was saying, guys, we should do functional programming. That was what the talk was about.
11:56Simon Jones:And he introduced a language called FP for functional programming. It was a very particular, somewhat idiosyncratic functional programming language, but there it was. So that was rather amazing, right? This was 1977. He was saying, guys, give up on imperative programming. Just do functional programming. Here's how you do it. But he also said in the same lecture, we might imagine designing new hardware to execute this new kind of language. So if you like, we've got Turing machines. They give rise to register machines and microprocessors and so forth. Maybe lambda calculus. Perhaps if we designed a machine from the ground up to do lambda calculus, it would look different.
12:37Simon Jones:So that was, of course, very exciting. and a similar kind of thinking led to an actual commercial machine called a Lisp machine that was a piece of hardware that was designed by Symbolics to execute Lisp programs. Lisp is a mostly functional programming language and so at the time I was you know in my early 20s we're thinking oh crumbs what would a piece of hardware look like that could was primarily designed to execute functional programs. We'd have a different kind of instruction set in architecture. So the newest we got to it, actually, was, well, there was a big strand of work then that was called the MIT Dataflow Project.
13:18Simon Jones:So Dataflow languages, functional languages, they're definitely the same kind of category, right? And so the MIT had this great group led by Arvind called the MIT Dataflow Group, and they designed, in the end, a machine called Monsoon, that was specifically designed to execute data flow programs, that is functional programs. It was based on a token store and matching and tokens flowing around and getting matched up and executing. You might imagine data flowing through a graph when three arrives at a plus node and four arrives at the other input of the plus node, bam, you could fire that plus node.
13:54Simon Jones:And the hardware did all of that. At a similar kind of time in England, my colleagues, Thomas Clark, Joe Stoy and others built something called the SKI machine SCIM. There's a paper about this in the FPCA conference and SCIM was designed to execute SK combinators so at the time David Turner's written lovely paper in which he described how to take lambda calculus programs and translate them into SK combinators. So you can read about that in my book. It's a very simple translation. You can give the whole translation in half a dozen lines but But then you have this mess of s's and k's. And s and k reduction is very, very easy.
14:40Simon Jones:So it's like the machine code of functional program, that's one way to think of it. What is a sk combinator, just for context? There are three combinators, s, k, and i. So they have simple reduction rules. Here they are. i of x equals x, kxy equals x, s, x, y, z is x of z applied to y of z. End of story. That's all. So very simple, right? So now all I've got to do is take my lambda, translate it into a giant tree of SK combinators, right? S applied to K, applied to I of 3, and S of Z. It's just a huge tree of S's and K's, right? Now simply apply the rewrite rules I gave you, and that is program execution.
15:25Simon Jones:It's rather astonishing that that can execute arbitrarily complicated programs, but it can. Do you think that's rather amazing? Now, then I can take an arbitrary Haskell program. I can translate it into lambda terms, and I can translate those lambda terms into S and K, very simple transformation, and I can just run those three rules, and it'll produce the output of the Haskell program. That's pretty amazing. And indeed, there is an implementation of Haskell that uses exactly this. It's called MicroHS, and my colleague Leonard Augustson has built it. And its execution mechanism is S-K combinator reduction.
15:59Simon Jones:And if you sit in micro HS, you can ask it to show you the S's and K's that it produces. If we had a shared screen, I could probably show you. So long story short, then, the SKI machine was designed to take SK trees, big trees of S's and K combinators, and just execute them directly. So it was built in hardware, and it ran perfectly well, reasonably fast. Now, why didn't this catch on? Why don't we have functional programming machines? I mean, at the time, it was a big idea. We even had a conference called Functional Programming Computer Architecture, FPCA. It was right there in the title of the conference.
16:43Simon Jones:But slowly, we became aware that what was really happening is we were doing at runtime what we could do instead at compile time. And that is always a bad idea. Imagine an interpreter for, I don't know, Pascal or something. Or for Java. We can compile Java to bytecode and we could interpret the bytecode. So then we're doing something at runtime. At runtime, the interpreter is looking at the bytecode saying, dispatching to say which instruction, blah, blah, blah. Now what does a JIT do? It takes a sequence of bytecode and says, oh, no, no. So I'm going to take that sequence of bytecode and compile it to a sequence of machine instructions that, when executed, will do the same thing, right?
17:30Simon Jones:Much faster. Because it can take advantage of bytecode sequences, for example, to say, you know, if you swap and then swap, it's a no-op or something like that.
17:44Simon Jones:So what in fact it turned out is this whole SKI business and any other, and indeed data flow machines also, was simply doing at runtime what you could do better at compile time. We were building an interpreter in hardware. So don't build the interpreter in hardware. Instead, build a compiler that translates your Lambda term into a sequence of machine instructions that, when executed, will behave as if you had done this reduction business. And then you might think, well, machine instructions for what machine? Well, from a practical point of view, it was very hard to compete with Intel. right? They were just spending bazillions of many years on making x86s go faster and ARM likewise for ARM.
18:32Simon Jones:So we can leverage all of that work by compiling into their instruction set. But even if you say you are God, you are the chief executive in Intel and can tell them to add new instructions or computation mechanisms to support functional programming, what would you add? Not very much. little bits to do with garbage collection barriers, I think, and such like, but nothing major. So, in other words, I think the whole build hardware to execute functional programming directly turned out to be a mistake. Inspiring mistake, fun mistake, I had a great time, but a mistake. It's better to build a compiler.
19:17Simon Peyton Jones:I would have thought there might be some unique opportunities for parallelism, given the immutability in these functional programming languages. So, yeah, you described that graph or that SK combinator graph. I imagine you could, you know, execute that all in parallel, assuming there's no connections across the graph.
19:40Simon Jones:And indeed, that was the data flow machine. The MIT data flow machine was all based on that idea. So you throw the whole graph into the token store and just run all the nodes that are runnable. But that's incredibly fine-grained. You've got to imagine this big tree of a million nodes, and your processor is sort of wandering around over it doing little things in parallel. There's a lot of memory traffic going on there. And these little threads are operating on the same bit of tree. Then there's synchronization costs. So very, very fine-grained parallel computation like this. turns out to be impractical, or not impractical.
20:18Simon Jones:You could do it, but it's very slow. So the data flow people, their history, if you look at the history of the MIT data flow project, they started with micro-parallelism. Every individual instruction was a separate parallel computation that might take place and the token store would match it up. And then they built more and more compiler technology that grouped these things together into larger units. So they expanded from micro threads of single instruction threads into 10 instruction threads or 100 instruction threads. But even that never really caught on. So you're right, though, that if I say in a Haskell program, E1 plus E2, then I can do E1 and E2 in parallel.
21:01Simon Jones:And GHC does support you in doing that. But nowadays, rather than expecting the compiler to do that automatically for every sub-expression, you can spark a computation. You say E1 par E2, and that says do E1 and E2 in parallel. There's a project at Carnegie Mellon for a strict language called ML that has a very good variant of parallel ML going in a similar way. So essentially, we've moved away from the dream of automatically getting parallel to very, very fine grain to programmer. We give programmer clues about where it's a good idea to do parallelism. But still the compiler will try not to fork two tiny grains.
21:46Simon Peyton Jones:I was searching on YouTube, and I've searched your name, and this video came up, and it said, Haskell is useless, Simon Fayton-Jones. And it's a video from a long time ago. Someone's got a low-quality handheld camera. There's a group of researchers that are all talking. Butler Lamson is across the table, and it's a fun little video. And in the video, you lay out this two-dimensional graph where on one dimension, there is the useful versus useless axis. And then on the other dimension, there is the safe versus dangerous. And then you're placing programming languages on this two-dimensional graph.
Read the full transcript
22:31Simon Peyton Jones:And I think you started by putting C as it's very useful, but it's incredibly dangerous. and then you put Haskell on the polar opposite side. You said it's useless, but it's very safe. What are the least safe and most useful languages, and why do you place them there, like C, for instance?
22:52Simon Jones:Well, yeah, so let's see. In C, you program my mutation, so it's unsafe in the sense that any function can mutate any variable at any time. You pass pointers around a lot, and functions mutate the memory pointed to by those pointers, And moreover, typically they can mutate it anywhere. There's no Ray-Bans checks or anything. So it's kind of like super unsafe. And in fact, and this is demonstrated by the fact, can you imagine that all of these exploits that we get every day, right, that Mythos is discovering in huge numbers, but we've had, you know, why is the internet so insecure? Primarily because all of our software infrastructure is written in unsafe languages.
23:32Simon Jones:If we, I mean, if we'd written all of our, you know, internet software, and operating systems in Haskell or maybe in OCaml or ML, 99 % of all these exploits would be removed by construction.
23:48Simon Jones:It's like we've built a boat out of paperclips and we're surprised that it's leaky. I mean, you shouldn't build boats out of paperclips, right, because they have holes in them. You should build it out of a secure substance, right, but then it's too late. So we spend incredible amounts of human ingenuity and effort patching the holes in our boat-builder paperclips. It's tragic. It's tragic how much effort and ingenuity and money is being lost and waste of resources just because we wrote our computational infrastructure for the world in an insecure language. That's what I mean by unsafe.
24:27Simon Peyton Jones:I mean, are there not vulnerabilities? Like if I wrote something in Haskell, I mean, there's got to be some new type of...
24:34Simon Jones:Of course there are vulnerabilities. I just said 99%. I didn't say 100. If I write a Haskell program that says receive message, if the message says, tell me everything, then spit out my entire database in reply. No language can stop you doing that, right? But if you look at the program and it doesn't have any such things, right? So, I mean, so, you know, nothing can prevent you against high level attacks to insecure programs. Or, I mean, another example might be deadlock, right? Two services, no matter how securely written, if A waits for B and B waits for A, deadlock. Sorry. No, and no language is going to stop you doing that.
25:19Simon Jones:You might hope for some high-level verification tools. But it's like, surely if you're trying to do something hard, like prove that that doesn't happen, You want to have a foundation that is, you know, in which you've got some bedrock to stand on. If you're standing on sand and trying to prove some advanced property, it's very, very difficult. But good point. I'm not talking about 100 % security. Absolutely not. But how many exploits are based on buffer overruns or, you know, pointer manipulation that's gone wrong? If you couldn't have a buffer overrun, you couldn't do pointer manipulation that's gone wrong, those exploits just wouldn't exist.
25:58Simon Peyton Jones:So, I mean, C's maybe half a century old now. What about more modern versions of those lower-level languages like Rust? Much, much better.
26:10Simon Jones:Much, much, much better, right? If we rewrote all of our software infrastructure in Rust, things would be way, way better. I'm not actually even sure whether Rust has array bands checks built in, but it must have the ability to promise that you're not indexing out. I don't quite know how, but if you compile your code with that switched on, you're a way better situation, way better. So, yes, this is not just functional programming, but you did ask about why I thought C was an insecure, unsafe language.
26:44Simon Peyton Jones:If we imagine that graph, there's the upper right quadrant, which is useful and safe. And you described that as nirvana in the video. And I guess maybe over time, I mean, C is somewhat really unsafe, really useful.
27:01Simon Jones:Yes. So C, I mean, Rust has moved along the axis from useful but very unsafe to stay useful and become safer. Now, Haskell started life as being very safe but useless. So it's worth just rehearsing that because in the first version of Haskell, there was no IO. The only thing, a Haskell program was a function of type string to string. It's functional programming, after all. It could do an IO. All it could do was take a string and produce a string. So obviously that's not very useful. It's a little bit more useful. A language that is very, very safe and completely useless is noob. That does nothing ever.
27:42Very safe, but very useless.
27:44Simon Jones:Haskell was a bit better, right? At least it lets you apply a function to a string and get back another string. So, of course, we then worked on how could we do IO in Haskell in a safe way. That will lead to, you know, monads and stuff. But so just as we're moving from C horizontally to go safer and safer, but staying useful. So from Haskell, we're moving sort of vertically to get more and more useful without stopping being safe. And Nirvana is when we sort of meet up, right? But the point is not to say one is better than the other, but just to say that we both seek things that are useful and safe.
28:25Simon Peyton Jones:When I think of functional languages, I guess in the mainstream or what people are kind of thinking about, I hear Haskell. I also hear OCaml. How do these two programming languages compare if someone was trying to pick a functional language to work with?
28:41Simon Jones:So OCaml is a strict language that is called by value. So when you say f applied to 3 plus 4, it'll add 3 plus 4 and then call f to get 7 right. In Ascol, if you say f of 3 plus 4, it'll build a little suspension that says, well, if you ever need this 3 plus 4, you can evaluate it, but maybe you'll never need it. And then it calls f. That's a lazy language. Now, so because OCaml is strict, it has a defined order of evaluation. so if you say f of 3 plus 4 and a second parameter 8 plus 9 it'll evaluate 3 plus 4 and then 8 plus 9 in that order right so it makes sense to say you can say f of print hello comma print goodbye right because you get hello and then goodbye printed so once you have a defined order of evaluation, then it's pretty easy to incorporate IO.
29:37Simon Jones:Even though it quotes a functional language, OCaml allows you to do IO without saying unsafe perform IO or anything. In fact, it has a defined order of evaluation and it's perfectly kosher to do that. As a sort of unintended consequence of being called by value, it was also by default impure. Now, good OCaml programmers won't use many side effects, but OCaml doesn't prevent you. Haskell prevents you. Why does it prevent you? Because if we'd allowed you to say f of print hello, print goodbye, those would be thugs, right? Not yet evaluated, right? So if f happened to evaluate its first argument and then its second, we'd print hello and then goodbye.
30:26Simon Jones:if it evaluated its second and then its first. We'd print goodbye and then hello. If it didn't evaluate either, we wouldn't print either of them. That doesn't sound very good if you want to control what I.O. is happening. Laziness forced Haskell to stay pure. Strictness allowed OCaml, which grew out of the ML tradition, by the way. ML is another functional language that predated Haskell. It was always strict, and it always had I.O. by default. it wasn't a goal but that's just the way it worked out at the time nobody thought about it it was just obvious so that's a big difference between OCaml and Haskell right is that now then since then they've both grown up Haskell's gained sort of monads OCaml's gained lots of lots of fancy type systems some of them look you know Haskell and OCaml have learned from each other OCaml has grown an interesting effect system recently and a whole lot of new extensions it's an absolute hotbed of innovation at the moment, OCaml.
31:24Simon Jones:So I view OCaml and Haskell as kind of siblings, brothers and sisters, right? We love each other. We learn from each other. We compete with each other. All of the things that siblings do. But they're not the same, right? So siblings don't say, I'm just better than you. You shouldn't exist. We say, let's enjoy our life together. And that's the way it is.
31:44Simon Peyton Jones:You described the laziness and the strict. And as a programmer, my initial thought is I would like to control the order of execution. And when I say print X and then print Y, I want it to happen in that order. Otherwise, it would be a little unintuitive. What is the main benefit of laziness?
32:05Simon Jones:Why is laziness good? Well, John Hughes did this rather well way ago, 1980-something. He wrote a program called Why Functional Programming Matters. And one of its main theses was that lazy evaluation lets you compose programs in a particularly modular way. So imagine a program that is, I mean, his classic example is a program that plays chess. So one thing you could do is you could imagine building a tree of all possible moves starting from the position we're at. It would be a very, very big tree. In OCaml, it would be too big. Because first of all, I'd compute the tree, and then I'd start deciding what move to do.
32:47Simon Jones:It couldn't possibly do that. Because the tree, of all possible moves, has more nodes in it than the number of protons in the universe. So let's not do that. Now, if instead you could build the tree, oh, having got this tree, supposing you had it, you could then walk over the tree saying, oh, let me do some minimaxing and saying, oh, this looks like a good position. Let me go this way. I could explore the tree, right? Now then, so in OCaml then, you would have to put the tree generation and the tree exploration in one function. In Haskell, with lazy evaluation, you can generate an infinite tree, and then the explorer that prunes the tree and explores just the bits of it that are necessary is completely modularly separated.
33:32Simon Jones:I can build a different generator and a different pruner. They're just completely separate programs. So lazy evaluation is very powerful glue that lets you glue together two programs that you'd like to be distinct. Strict evaluation forces you to merge them together.
33:52Simon Peyton Jones:Yeah, this reminds me, I mean, so in Python, for instance, they have the idea of a generator where you can lazily retrieve things.
34:01Simon Jones:Every strict language, every serious strict language has lazy evaluation in it. They're called iterators or generators. And so does OCaml. But in Haskell, that's the default. Now, instead, in Haskell, so this is a bit like, again, the two are converging on the middle. Haskell, lazy by default, but you can make things strict. You can put in exclamation marks to say, please evaluate this before the call. Or the IOMonad to say evaluate, but that's a more brutal, strict annotation. So in Haskell, you can make things stricter. in OCaml you can make things lazier right so it really boils down to is what's the default we both want to have a mixture of the two and then it becomes a bit cultural as to which you prefer um I I don't know some people sometimes ask me they say well if you were designing Haskell again would you make it strict by default with really good support for laziness.
35:02Simon Jones:And I often say, well, I might. Yeah, it does seem attractive because frequently I find myself cursing laziness as an implementer. But I strongly suspect that 10 years after that, I'd be thinking, man, if only it was lazy by default. Oh, when I say strict by default, I would definitely mean strict but pure. Right, no side effects.
35:26Simon Peyton Jones:A few times in our conversation, you've mentioned the word monad, and it seems like it allows us to do the side effects. What is a monad, and how does it help us do side effects and preserve ordering?
35:41Simon Jones:One way to think about it that's very easy to understand and use is just to imagine that the do notation is somehow built into Haskell. So you can say do print x semicolon print y, and that has type IO unit. So a value of type IO unit means I do some input output and return a value of type unit. An expression of type IO int is an expression that when you run it will do some IO and return an int. Okay? So do lets you combine IO performing computations together. So print3 has type IOUnit. It does some I.O., namely printing3. Getchar has type I.O.char. It does some I.O., namely reading a character from standard input and returns a character.
36:44All right.
36:45Simon Jones:Notice that's different from just char. So, you know, quotes, X quote, that has type char. It's just the character, pure. Get char, the IO-performing operation, has type IO char. It does some input-output and returns a character.
37:03Simon Peyton Jones:Okay.
37:04Simon Jones:The do notation lets you combine together IO-performing computations. So if you could say do, and then you say X, left arrow, get char, semi-colon put char x then that x left arrow get char that says run the get char computation and get me the character, call it x the put char x says run the put char computation to put x and we combine them together with the do notation that combines two two computations to make one IO performing computation right so but these things are Completely first class. That's what's new about monads compared to just make it into C. X left arrow, get char semicolon, put char X.
37:55Simon Jones:That's a computation whose type is IOUnit. Let me give it a name so I can say let foo with type IOUnit equals that do. Now I can pass foo as an argument to something. I could put foo in a data structure. I could return foo as a result. It's a value just as much as three. or plus.
38:20Simon Jones:In particular, for example, I could say do foo, semicolon foo. That takes foo, uses it twice. Each time, do foo, semicolon foo says do foo, and then do foo again. Right? So I'll read a character and print it, and then read a character and print it again. So these values of type iot, for some type t, are first-class values, right? In C, I can't take x colon equals 3 semicolon, you know, y plus 4 and pass that as an argument to something and expect it to happen wherever it's used, right? It's not a first-class value.
39:03Simon Peyton Jones:When I first was learning this monad idea, it seems like you've said in a few places it's a way to do the side effects but keeps the language pure. but when I saw it, my first thought was, it's almost like this little place where we segregate the dirty things we want to do, I guess. But then how does that keep the language pure?
39:26Simon Jones:Oh, because we are not, but look, if your function has type int, I want int, can it do any I.O.? No. No. If it has type int to I.O.int, it could do arbitrary I.O. So yes, so it's nice, pure int to int function or dirty int to int function. So you may say, perhaps you're about to say, that's a bit of a blunt instrument. Either completely pure or completely dirty, right? It gets you an awfully long way. But nevertheless, it would be cool if you could say, oh, I am int to effectful doing reading of files only int. So in the type, you'd like to say, what kind of effects can it have? Can it throw exceptions?
40:26Simon Jones:Can it spawn new threads? So you'd like to enumerate the effects this computation could have, right? That would be cool. That's called an effect system. And there's, you know, a bazillion programming language papers about effect systems. And it turns out that you can indeed, in the type system of Haskell, and indeed OCaml is rapidly becoming the same, you can express not just all or nothing, does it do IO, game over, but rather which particular effects does it do, including no effects at all. That's pure, right? A good place to start is a library called Bluefin, which my colleague Tom Ellis has designed.
41:13Simon Jones:It's a very nice take on how to do effect systems in Haskell.
41:17Simon Peyton Jones:I guess the purity comes from that this dirty stuff is signaled through the type system. Correct. Correct.
41:27Simon Jones:So we can do it, but here it is, and be aware. Yeah. And because you have to thread, because the type system gets in your face, you were trying to, like map, say. No. Map says I apply a function to every element of the list. Well, so it has type A to B to list of A to list of B. If you want to apply an IO performing function, so the function you're applying has type like int to IO of char, You could map that over a list, but you just get a list of I.O. of chars. That hasn't done any I.O. yet, right? You want something that says, take a list of I.O. chars and perform those actions one at a time.
42:10Simon Jones:So I want a function that goes from type list of I.O. char to I.O. of list of char, right? And you might want to perform all those actions top to bottom, or maybe bottom to top. Who knows? That's what this function of type, you know, so yes, so you could do it in various ways. So sometimes it gets in the way, right? You say, oh, shit, you know, can't I just use map? Well, in Haskell, no, sorry. You're going to have to do a little bit more work to tell me in what sequence you want your effects to happen. Because by default, Haskell does not specify sequence. So, you know, adding monads to control effects does get in your face a bit.
42:54Simon Jones:And that's the tax we pay. In effect, that's part of the big experiment that Haskell is doing, is to say, suppose we upfront say we're willing to pay that tax. You know, how many followers can we get? And the more, but I will note that monads have infected quite a lot of other languages. Like F-sharp is definitely called by value impure language. And yet F-sharp had these workflows that were definitely monads, right? and monads have you know appeared in scala and in many many other languages so something that's very monad like has appeared lots elsewhere it's been a very unifying concept open ai anthropic
43:33Simon Peyton Jones:cursor and versell all use this product to make their lives better and the problem it solves is when you're building sas or an ai product and you want to sell to other companies there's all these requirements you need to meet. There's SSO, there's SCIM, there's RBAC, there's audit logs. These are all things that take time to integrate, but aren't the main focus of your app. WorkOS is an API layer that lets you meet all of these requirements in just a few lines of code. So let's say you have a new SaaS product and you want to sell to other companies. WorkOS will solve all of these critical feature gaps for you.
44:08Simon Peyton Jones:You can check them out at workos.com to learn more and get started. And I appreciate them for supporting my work and sponsoring this podcast. When I read about Haskell and people's perception of Haskell, one thing that keeps coming up is that the type system is really powerful. And so I kind of want to ask you, maybe just even on the highest level, what is a type system in your words? Okay, so what does a type system do?
44:37Simon Jones:It lets you reject silly programs up front. So if I have a function that adds one to things and I apply it to a character or to an IO computation,
44:54Simon Peyton Jones:I'd like to, that's going to fail at runtime.
44:58Simon Jones:Because I can't add one to a character. Or maybe you overload plus, maybe reverse a list or something. If I've got a list reverse function and I give it something that just isn't a list, then it's a bit silly to allow that and only fail at runtime. So fundamentally, type systems are about rejecting at compile time programs that you do not want to run because they will fail at runtime. Okay. Now, we've had static type systems for a long time, like going back to Pascal and earlier. But simple type systems are annoying because they get in the way Imagine a function that reverses a list in Pascal You could write a function that reverses a list of integers But if you wanted to reverse a list of characters Sorry You can't let that function that reverses a list of integers it has type List of it to list event, so you can't apply it to a list of characters Game over You have to write another copy of the code with a different type.
46:06Simon Jones:That's a bit annoying. So what are we going to do? We need polymorphism. We need a more powerful type system. We want to give reverse the type for all A, lists of A to list of A. So that up front says, I work for any type A. You give me a list of integers? Fine. I'll produce a list of integers. You give me a list of characters? Fine. I'll produce a list of characters. Notice that's much better than just list to list. I want to keep the fact there's a list of integers, so I know if I apply, when I look inside the list, I know I've got an integer. But also, if I just list the list, I might get back a list of some completely different type.
46:43Simon Jones:But I know that reverse returns a list with the same type of things. So parametric polymorphism, super valuable. If you want a sciatic type system, you must have parametric polymorphism. The message is, if your type system is too simple, it gets in the way. Very important lesson, because it means that we cannot really say, is a type system useful or not, unless we say, which one? Because we know that weak type systems are very inconvenient. It must at least have parametric polymorphism. And that is another idea that was born in the world of functional programming. It was born in ML, incidentally, Robin Milner's famous dictum, world type programs don't go wrong.
47:28Simon Jones:ML was the first, I think, the first parametrically polymorphic functional programming language. But generics in Java and object-oriented programming more generally is exactly the same idea, right? So there's an idea that was born in functional programming and made its way into the mainstream.
47:43Simon Peyton Jones:And you mentioned polymorphism. And so there's this parametric polymorphism in the type system. but in the example you mentioned where maybe you want to do an operation on a list and then the type of the input changes I was just thinking what about when people do polymorphism in the
48:03Simon Jones:classes yeah okay but so now you're into a whole more complicated world right so as soon as you say class you're talking static type system again right so object-oriented programming is is another approach to polymorphism. So in an object-oriented language, we say if we have a Ford that is a car and a car is a vehicle, then anything that works on vehicles should also work on cars and should also work on Fords. So the code that we write for cars works unchanged for vehicles and for Fords. OK? Now, that's a form of polymorphism, not parametric polymorphism. That's what you might call object-oriented polymorphism or subtype polymorphism.
48:51Simon Jones:OK, so now we put polymorphism in the sense that the same code, the same executable code, actually the same machine instructions work on values of different types. OK? In both cases. Both reverse a list, same machine instructions. Code that works on vehicles works on things and forwards, same machine instructions, right? Okay. That's what polymorphism in general means. Parametric polymorphism means this for all A, list of A, list of A stuff. Subtype polymorphism means if it works on vehicles, it works on any subtype of vehicles. Okay? Now, the interaction of the two, which you get by adding generics to an object-oriented language, is pretty complicated.
49:36Simon Jones:Oh, and by the way, adding side effects as well. And that's why you're, and so your question involving classes and superclasses and so forth is smack in that complicated world. And I'm not sure it'll be very fruitful for us to, you know, we'd have to get a lot more details of the type system sorted out to know what to say. But at this very high level overview, my sort of, the big point I'm trying to make is weak type systems get in the way. Type systems are meant to reject programs that will go wrong. But my function that reverses a list of integers, it will also reverse the list of characters.
50:13Simon Jones:So it's tiresome to be told, no, that is a bad program. I want to be able to write that it has that full A list of A to list of A. So the idea of making a type system more complicated is to say programs that you want to run, you can still write in your static type system. Now, you might say, well, blimey, if that's all, why don't we just get rid of the static type system altogether? Now we could run all of those programs, but the trouble is you can run too many programs now. You can run programs that will crash at runtime, and that's very very very bad. We all know the costs of programs that crash in deployment, that you could have crashed before you even started to run them, before you even ran your first test.
50:56Right?
50:57Simon Jones:Before you even linked it into an executable. that's really good but the biggest benefit of a static type system in my humble opinion is maintainability if you have a program written in i don't know pearl or ruby um or um lisp in its basic form um and it was written 15 years ago and the original author has left and all of the people who were involved at the time it was written have left then that program is very difficult to maintain. And it becomes almost immutable. Nobody dares change it anymore. What they do is, it's an immutable piece of software, and you do that stuff around the edges to impedance match what you really want to do to this now immutable blob.
51:41Simon Jones:So of course, you have lots of tests. So test-driven development, I'm totally with it. I've done all of that. But still, GHC, for example, is itself written in ASCOL. It's 35 years old, and yet I do large-scale, systematic refactorings of it, you know, fearlessly, because the type system keeps me safe. In fact, often what I'll do is I'll change a few types and then start compiling, and then a sort of wave of changes propagate through, forced by, you know, I just get type errors, so I know what to do. Whereas the thought that I've changed the representation of this data structure a little bit, I've added a field to this data structure, where in the entire compiler might that field be read, written, or freshly allocated?
52:26Simon Jones:I can't imagine how anybody maintains 30-year-old software and makes large-scale changes like that without a type system. It's unimaginable. So for me, the benefit of type systems is maintainability. Oh, and designability, right? So a type, I often write the types of my programs up front. I write the type, you know, the data types are super perspicuous. Now, if I say, it's a bit like writing the classes of an arbitrary language, right? But if you have no types, no classes, nothing, just, I don't know, S expressions. Types are my design language. They're the way that I start writing my designs.
53:06Simon Peyton Jones:I'm trying to understand the other mindset. like let's say C for instance where I remember a lot of stuff when I was learning it in college for instance many times right I'd add a character to a pointer or something and it just works because it interprets the character as a number um so is there any value to having that kind of type system or is that just strictly unredeemable just you're stronger I think there's no benefit to weaker just off the top of my head one thing i think of is there is a set of programs that will work but don't satisfy the type system yeah that's right that and but those are i mean i don't know
53:53Simon Jones:if they're good that's subjective oh no they may be good so so so so uh that like us like we started if you have pascal and you write a function to reverse a list of integers then if you apply it to a list of characters, the same machine instructions would work, but it is rejected. Right? So we have rejected a perfectly decent program. Bad. Right? Our goal is to expand the collection of programs that satisfy the type system, to include as many as possible of the programs we want to run, without including any of the bad programs that we don't want to run. Okay? Okay? Parametric polymorphism is a big step in that direction.
54:38Simon Jones:Other type system innovations are a big step in that direction. But there will always be some programs that would run perfectly well that the type system rejects. Imagine a tree that contains integers at every node. But if you are 17 deep in the tree, or 34, or 51, if you're a multiple of 17 deep, the integers can be characters instead. Or the integers all turn out to be characters, right? Now, you could write a program that generated such trees, and you could write a program that consumed such trees, knowing that every 17th layer we switch to characters. but most static type systems would make it pretty hard for you to accept that program.
55:31Simon Jones:And yet it will run. Now, you might say, oh, but I really want to write that program, guys. You know, don't get in my way. Well, then we should provide a way for you to bail out into dynamic typing. Right? What I'd like to do is to say, okay, so if all else fails, then at least you can, as it were, pair up a value with its type representation. Because one reason we don't want to interpret an integer as a double position float, for example, is that they don't even have the same representation, which is just nonsense. One possible way, which untyped languages let you do, is to tag every integer and every double position float with the fact, I'm an integer, I'm a double position float, but that has a lot of overhead.
56:19Simon Jones:So one merit, I think it's not the biggest single merit, but it is a major merit of a static type systems, is you have no tags. You know that if it says it's an integer, it's going to be an integer. You know that if it's a double position float, it's going to be a double position float. But if you're not sure, maybe we could make a way to make a pair of a type representation and this value. The type representation is now like a runtime tag. It's like a little runtime data structure that describes the type. And then in your program, you could say, now I want to say, oh, I've got this type dynamic.
56:54Simon Jones:We'll call this pair a value of type dynamic. Now, when I want to take a value of type dynamic and treat it as a character, I want to say, oh, look, look at the type dynamic. See if it says it's a character. If it is, return the character. If not, crash. Right, runtime failure. That's fine. You can do that. So, and Haskell has good support for dynamic typing where necessary. So my story would be static typing should expand to carry as much as possible. And where you absolutely cannot do it, sorry, then use dynamic typing. And we provide facilities to support that.
57:30Simon Peyton Jones:One thing I wanted to talk with you about is the compiler. How does the GHC work on a high level?
57:37Simon Jones:So GHC takes a string, like any other compiler, the source code of the program, parses it. And then it type checks it, figures out, is this a type correct program? Then it converts it to lambda calculus. Now, Haskell, the Haskell AST, the original source tree, has 50 different data types, It's very different kinds of nodes, some of which have 30 or 40 different variants. So it's a really big, diverse, complicated data structure, the AST. Lambda calculus has this variant of the lambda calculus has eight. One data, maybe two or three data with eight constructors. So it's like taking a gigantic language and squeezing it down into a tiny one.
58:35Simon Jones:And that tiny one, we can then optimize, right? That's the optimizer works on that. So the front end does parse, rename, type check, desugar into lambda calculus. That's the front end. The lambda calculus particular language is called GHC's core language. I'm quite proud of it because it's been very, very stable. It's 35 years old and it has barely changed since birth. That's amazing, right? Because Haskell has changed a lot, a lot. So almost all of the innovation in Haskell has been in the front end. Very little in core. Now, the back end, the core optimizer has changed a lot too. But all of the changes that were useful there would have been useful 30 years ago.
59:27Simon Jones:So they're two completely acceptable things. So I'm quite proud about that. Core, then we do a lot of core-to-core passes. that simply take core programs, which is core programs. Lots and lots, long pipeline. Then we convert it to C minus minus, which is a prototypical imperative language. Think of it as a portable assembly code. So that bit is meant to be platform independent. So it's simply, that's the compiler that takes. Do you remember I said if you take lambda calculus and compile it? That's that step. I want to compile the lambda calculus into machine instructions, really. But I don't really mean machine instructions.
1:00:05Simon Jones:I mean portable machine instructions. That's called C minus minus. Then I want to convert C minus minus into actual machine instructions for various platforms. And then we could either do that directly with the native code backend or go via LLVM. Interesting.
1:00:19Simon Peyton Jones:I've never heard of C minus minus. Why not just go directly to, I would have thought, maybe assembly or something like that?
1:00:25Simon Jones:Well, because what happens is assembly for which processor, please?
1:00:30Simon Peyton Jones:Oh, I see. I guess it's the, I would have thought the lambda calculus part was already portable. So you just. It is, yeah.
1:00:38Simon Jones:You could go straight, but so there's work to go from lambda calculus. You could go all the way to x86. Then throw all that away and now go from lambda calculus to PowerPC. Oh dear, I've just duplicated a lot of work. by going from lambda calculus to C minus minus and then from C minus minus to x86, C minus minus. We've avoided duplicating the work that went from lambda calculus to C minus minus, right? When you see it like that, it's pretty obvious, isn't it? You want to make the platform-specific bit as small as possible. You would like to have, as it were, like a generic architecture, one that can do addition and has a program counter and a stack and so forth.
1:01:21Simon Jones:that's all C-minus-minuses. It's just a portable assembly language. And then you say, oh, the nitty-gritty of, you know, whether you have double precision add and set the floating point bit here and there.
1:01:31Simon Peyton Jones:That, well, that's platform-specific.
1:01:33Simon Jones:Core is itself statically typed. You know, but in some ways it's surprising because no other compiler has this property, no other production compiler. By core is statically typed. I don't just mean that the initial program was typed correct. I mean that a core program, you can run a type checker on that. I might say, why do you need to? But after all, if GHC is correct, it started with a type-correct call program, because it came from a type-correct Haskell program, assuming the desugarer was right. And all the optimizations, if they're right, will generate a type-correct call program. So why do you need to type check that?
1:02:06Simon Jones:Answer, to discover bugs in GHC. Now, these are serious bugs, right? If you ever take a type-correct call program and an optimization pass produces a type-incorrect call program, what will happen if we don't have the type checker for call? We'll generate machine code and we'll run it and we'll get a seg fault. Now we have to backtrack from a particular test program that now crashes all the way to back up the pipeline, up the pipeline, up the pipeline, up the pipeline. Oh, it was this pass. of GHC that was faulty. That's super hard to do because you know you're getting out GDB on some runtime failure that is an indirect and perhaps distant consequence of the fact you just generated a type, you know, you just made a, you had a bug in the optimizer.
1:02:59Simon Jones:So it is amazing to have a type checker for core. Now why does nobody else do this? Well it's because their intermediate language Typically, and I really am talking typically because I know of no other compiler that has this property, none, production compiler. Typically, then, they're complex syntax trees decorated with all sorts of pragma information and things hanging onto it here and there. And there's no type checker for it at all. And there's no hope of one. So I'm very proud of the fact that core is statically typed. and I also think it's a the most delightful thing is that the way that it is statically typed it is an implementation of something called system f so system f, when I said lambda calculus lambda calculus as Alonso Church had it was untyped, had no typed system at all but Girard defined something called system f which is a statically typed lambda calculus a rather powerful one and core is essentially system f so we literally adopted something from the nerdy theoretical computer science you know logic community logic of mathematics community and adopted it directly in a in a production implementation so i'm very proud of that um i think core is and the fact that we can do we have 35 years worth of development that has been not just not impeded but actively aided by statically tapped into media language is really a big marker in the ground.
1:04:34Simon Peyton Jones:Watching all your talks, reading everything, one of the interesting data points that you brought up was that Haskell is talked about more than used when you compared Stack Overflow volume and actually GitHub volume, like who's actually using the programming language. Why do you think that is?
1:04:55Simon Jones:so Haskell embodies one key idea immutability changes everything there's a quote from Pat Helen's talk that I think you also paper which I think you also looked at already so it says programming with values changes everything about the way you think about programming it's just mind changing it's not necessarily better but it is different and so Haskell takes that idea and runs with it. Everything is driven by that one idea. Everything else is incidental. In the early days, that meant we just said, well, guys, suck it up. We'll keep changing the language. And if it breaks your programs, too bad.
1:05:34Simon Jones:So it is a bit peculiar. And therefore, also, it felt a bit academic, because initially it was really not very powerful. It was taking the key idea, but you couldn't do very much with it. We talked about that, right? So over time, GHC and Haskell in general has become more and more powerful. The type system has become less and less in your way, the more and more useful. All the obstacles that make functional programming hard have become better. The compiler generates faster code, it can browse faster and so forth.
1:06:02Simon Jones:So it has become less, if you like, peculiar. So we've become more and more taking into account the needs of our users. But in a way, the sort of cultural heritage is we never give up on the one core principle. We're just not going to give you unrestricted side effects. Sorry. You've got to say unforeseen before my own and put up with the consequences. So we're going to stick to one core principle, and then we'll do lots of work around the edge to make that better. Right, so that does limit our community somewhat, right? It does mean you really have to think in a different way. Immutability changes everything.
1:06:38Simon Jones:That means you'd have to think a different way about programming. Maybe you don't want to think in a different way. That's fine. Then don't use Haskell, right? So in a way, we started from a very small user community, a very sort of pure and nerdy one, and growing larger and larger, but all slowly, slowly, but all the time maintaining faithfulness to this core principle.
1:06:57Simon Peyton Jones:I thought that was very unique about Haskell because I feel a lot of the other programming languages are user-centric. I mean, if people want something, they work on it, they add it. Whereas Haskell feels more principled or it's all starting from these ideas. And if you don't satisfy these ideas as a user, yeah, well, that's fine. for instance in one of your talks you mentioned somewhere that there was a release of the compiler where if a file wasn't type correct then the compiler would delete the file oh it reported the error message first yeah i reports there but i thought that was that was absurd i mean very hostile i guess to the i mean well it's if you're type safe no problems but
1:07:49Simon Jones:Oh, it was a mistake, right? It was a bug. It wasn't deliberate. And it only happened, you know, how did the bug get out? Because, of course, if it always did that, we'd have noticed. How did it get into a release? Well, it was only on Windows and only when you compile a module that was not in the current directory. But at that stage, our users were very forgiving. And, you know, somebody wrote to us and said, well, by the way, Simon, you might like to know that, you know, GHC does this. But, hey, don't worry about it. You know, I just copy all my files somewhere else before I compile. and then I can't bring them back.
1:08:21Simon Jones:So, of course, those days are long gone. We pay a lot more attention to our users and have much more rigorous CI testing than ever we did. So that's a story from a long time ago, but it's a good cultural story, because it suggests that we care about our users very much, but we care about users who in their hearts want to be principled. We're trying to appeal to. One of the things I like best about Haskell is people often say, I just enjoy writing Haskell. right it's fun right my boss doesn't allow me to because you know it somehow doesn't fit with my production shop and i but but for me i would go for i love writing this stuff every time every time
1:09:04Simon Peyton Jones:that's that's very rewarding to me there's also this interesting i don't know if it's a cultural value but it's a statement that you say often in the context of these older talks you say that you to avoid success at all costs. Could you explain what you mean by that phrase?
1:09:21Simon Jones:Oh, yeah, this was just a little play on words. It was in a retrospective on Haskell. I gave an invited talk at Popple a long time ago, probably 20 years ago. So it's a little play on words because you can read it as either avoid success at all costs. And that's what we've been discussing. Success at all costs means compromise your principles in order to satisfy your users or think that you're satisfying users. You know, give them what they say they want. Where, more, if we build it, they will come kind of deal, right? So avoid success at all costs. Or if you parenthesize it the other way, it says avoid success at all costs.
1:10:05Simon Jones:Or at all costs, avoid success. And that's saying, that's a little joke, but it says if you're too successful and have too many users, it becomes more difficult to make changes. and we experience that right now so i devote many many more of my personal cycles to backward compatibility issues than ever i did i have devoted hundreds of hours you know hours and hours well days and days weeks and weeks in the last year or two to the following what seems to be a very simple property if if you can compile a program a package in a whole program with GHC 10.0 and we released GHC 10.2, you should be able to compile that same package unchanged with GHC 10.2.
1:10:53Simon Jones:Seems reasonable, right? After all, 10.2 should just be better. But no, GHC has never had that property. And making it have that property has turned out to be very, very time consuming. Previously, we just never cared. Then we started to care, but thought it was a lot of work. And now we're investing the work.
1:11:12Simon Peyton Jones:I guess that was from a long time ago. I think nowadays, software engineering, there's been a major shift in the last year where a lot of code is being generated by these models or these LLMs. How do you see programming language design shifting to accommodate a world where a lot of the code is no longer written by humans?
1:11:33Simon Jones:I think it may be the best thing that's happened to statically typed languages for a long time. because, as we've been discussing, with a static type system, you cut down the space of programs that the LLM can generate because it is perfectly capable of running the compiler and saying, oh, darn, that was a bad program. Better fix it. So a zillion iterations get done behind the scenes. Whereas in an untyped language, the first one it coughed up, you'd have had to run or run against its test suite or who knows what. But it drastically tightens up that cycle, right? So I think that statically typed languages are a huge boon for LLMs because it's too easy to get.
1:12:19Simon Jones:Programs are just strings, right? We could just generate the next plausible word. And you want to make any implausible programs, programs that really shouldn't run, you want to make them not run right away.
1:12:32Simon Peyton Jones:If there's a slider on, I guess, the strength of a type system and the other sides of the week, what do you see as the absolute strongest type systems among programming languages? Oh, Haskell, I think.
1:12:45Simon Jones:Haskell is exploring the bleeding edge. There is an exception, which is that module systems are a, and in particular sort of functor style module systems, are explored much more deeply in the ML OCaml world. and in the Haskell world we've essentially never gone there but otherwise I think Haskell's right up there. Now of course a language like Scala is also so Scala has almost everything Haskell has I think not quite but it also has subtyping and object orientation so that's a lot more complicated a lot more complicated I think and they pay a price for it. I think Martin Odeski would agree that they pay a price for it.
1:13:36So in complexity,
1:13:38Simon Jones:it's probably more complicated than Haskell's.
1:13:44Simon Jones:Maybe in terms of power, so maybe I should have said Haskell and Scala are the two leading. Haskell, Scala, O 'Cammell. Perhaps I'll just put them in an equivalence class for now. They're not strictly comparable. They all have things in which they're more powerful than the other probably.
1:13:57Simon Peyton Jones:What do you think are the important problems to solve in the future of programming languages today? Maybe, you know, what are the unsolved problems in the domain that are top of mind for you?
1:14:08Simon Jones:I think it's actually hard to identify, you know, to say, here's a problem we want to solve. Let's try to solve it. Well, I think another way to tackle is to say, what are interesting, you know, new languages out there that are exploring very different parts of the design space? And there, I think I do have a candidate. So the language that is my day job, I work for Epic, and we're designing a programming language called Verse. Now, Verse is a very exotic language. It's really a functional logic language. So it's yet more expressive than Haskell. It has a photonic type system, but a very different one to Haskell's.
1:14:44Simon Jones:So if you like, the way I think of it is like this. If you look at C and Fortran, they look pretty different if you're an imperative programmer. But if you look at them, if you zoom out, still you can see functional languages, then C and Fortran are pretty close together, you know, along with object-oriented languages, they're all in a clump, right? And then there's some functional languages, you know, Haskell and ML and OCaml and Scala out here. If you zoom out still further, then the imperative languages and functional languages are all together, and VERSE is way out here, right? So VERSE is exploring a very new point in the design space.
1:15:19Simon Jones:But just like functional programming back in 1980, it seems sufficiently interesting and cool and unusual and weird that it's worth exploring, right? So back in 1980, nobody said, we're definitely going to do functional programming and it's going to be useful for practical applications. They said, that's pretty weird. By all means, give it a try, guys. And that's kind of what I am with Verse. One difference is that back in 1980, we were purely academics. And now, but Verse is being developed by, well, Epic Games. So we've got much more muscle behind it than was behind functional programming to begin with.
1:15:54Simon Jones:So we'll see. It's a very interesting intellectual endeavor. Adventure, I should say.
1:15:59Simon Peyton Jones:Yeah, I think a lot of people, like students, they may be worried about AI or studying computer science. Would you recommend people learn how to program today given that AI is starting to write reasonable code now?
1:16:13Simon Jones:Oh, yeah, yeah. So I think people are right to be worried in the sense that I think there's going to be considerable dislocation. If you were in the Industrial Revolution, then lots of people lost their jobs as spinners and weavers. And it wasn't easy for them to get a new job in the new economy. Now, the new economy had, in the end, had more jobs. But if you were one of the people who just lost their job, that was not a happy place to be. From our perspective, Olympian perspective, every few hundred years later, we think, well, it's just a blip. If you're part of the blip, problem. Right. So I think the right to be worried.
1:16:52Simon Jones:We don't know how things will shake out. I'm actually optimistic that in the medium term, if we don't destroy ourselves with some truly existential thing. But from an employment market point of view, I'm optimistic that in the end, you know, we'll just be in a higher place, that AIs will just be a bigger power tool. I mean, everyone, we like using compilers, right? We don't like machine code anymore. Compilers make us more productive. Maybe LLMs could make us more productive. That's what I hope. I sort of believe modulo dislocation effects. Now, should we teach children or even undergraduates how to program?
1:17:30Simon Jones:So I think still yes. The reason is because one way to say it is co-pilots need pilots. right i think copilot was quite a good title that moksoff gave their tools right because it encourages you to believe it's your partner not your boss if lm spit out a pile of goop and we literally do not understand what it does we just try it and it kind of works that might be okay if we're just throwing up a quick visualization it might be less okay if the quick visualization is going to drive our policy choices about as a nation whether to go into lockdown because of covid or if this program is going to run my airplane or train a signaling system.
1:18:15Simon Jones:So now those are extreme ends of the spectrum. From quick and dirty things, it really doesn't matter if it doesn't work, but it kind of does a lot of the time. Absolutely fine. Two, this is a 30-year code base. It's going to last a long time. I really want to make sure that it's like putting new stuff into GHC. If somebody sends me a pile of AI-generated code to put into GHC, I'm not going to put it in unless I've reviewed it or somebody's reviewed it because in 10 years time, I'm going to want to change that code. How do I even know what it does? If it's simply a magic incantation that somebody's done that kind of worked on the test they did, but maybe won't work in deployment, that's no good.
1:18:51Simon Jones:So I really want long-lived maintainable code to be well reviewed. Sorry. And to do that, I need reviewers who can write code. Let me mention one other perspective. If you think about what every child should know, when I think about what every child should know about computing, I would include binary and bits. Just as for physics, I would include atoms and molecules. Now, it's not that in real life anybody manipulates atoms or molecules or takes decisions which are based directly on knowledge. of knowledge, but somehow knowledge that all matter is made up of atoms, you know, constituted of a finite number of elements, that knowledge underpins everything we understand about the natural world.
1:19:42If you literally had never been told that, you are sort of emasculated
1:19:48Simon Jones:even as a citizen, let alone as a scientist. So if you literally do not know that everything is composed of bits, that words and music and text and LLMs and everything is all just bits, I think you're crippled. So I want every child to learn, you know, it's like I want you to learn the bottom. It's all bits, nothing else. It's all just bits. I even have a talk. The talk is called Bits with Soul. It's easy to grep for. It's a talk I gave to an audience that was not a computer science audience at all. It was a completely lay audience, ranging from 14-year-olds to professors of quantum mechanics.
1:20:26Simon Jones:Pretty difficult audience to address. It was meant to be all about codes and coding and bits. So it tries to get at the essence of why do I think it's important that every child, every person, every human being should understand something about the computational universe that surrounds them. And that is founded in bits. Now, just to develop the analogy a bit further, I would then say, and it also, I think I want them to also know about programming, programs. I want them to know that computers fundamentally execute by following machine instructions blindly, right? That is not magic. It's not hocus pocus.
1:21:02Simon Jones:It's just remorseless and very dumb, right? It's incredibly empowering then. And also to learn the basics about how neural networks work. In the same talk, I explain how a one-neuron neural network works. And that's enough. Then it's actually true to say, not distorting the fact to say, ChatGPT is just a trillion of those wired together. And astonishingly, that very simple... So all ChatGPT is is a trillion floating-point numbers and a lot of floating-point arithmetic. That helps you to make sense of a question like, can ChatBGPT have feelings?
1:21:47Simon Jones:Well, it gives you... Of course, that's a philosophical question, but it informs your discussion about it if you know that all it is is trillion floats and a lot of floating-point arithmetic. That's all. Nothing more. Anyway, sorry, long answer to your question. So, yes, basic programming, absolutely. Yeah. Becoming very skilled in how to use Web Django framework 2.7, maybe not so much. Maybe. I think one thing that LLMs are very good at is knowing the arcane and complicated APIs that many of these frameworks present. There's just 10 ,000 functions you've got to know. And LLM is really good at knowing that.
1:22:32Simon Jones:I don't want to learn them.
1:22:33Simon Peyton Jones:You mentioned somewhere, someone asked you, what's your favorite programming language? And obviously Haskell's got to be number one. But for your second favorite programming language, you said it was Excel. At that time, why was Excel your favorite programming language?
1:22:49Simon Jones:Oh, because it's the world's most widely used functional programming language. The formula language is a functional language, isn't it? Doesn't have any side effects. You program entirely with values. So the formula language of Excel is a functional programming language, a very weak one. It doesn't even let you define new functions. And it has a very limited collection of data types, namely just flat arrays and numbers and strings. So when I was working for Microsoft, I took it as my, what's the word, war cry to say, let's take that idea. Excel is the world's most widely used functional language by three orders of magnitude.
1:23:34Simon Jones:And, oh, it's the world's most widely used programming language by three orders of magnitude. Not just functional language. Excel is used by many, many more programmers, users, domain experts, than any imperative language. Right? Imperative language is a few million users. Excel, hundreds of millions of users, right? Even if you just restricted users who are using formulae. So how can we delight those users? Answer, take ideas from functional programming and use them to make Excel's formula language more powerful. It took me 20 years, but Excel did finally add Lambda to Excel. Look it up. There are blog posts about it and many YouTube videos about it.
1:24:24Simon Jones:So you can now program in Excel using full Lambda as Alonzo Church originally defined it. You can write anything. Like because Lambda is computationally complete, you can write any computation in Excel. Now, it would be a bit slow, but you can. And much more practically, you can take formulae that previously you just copy pasted here and there. and you wanted to make reusable, wrap them up in a Lambda, and now you can just call the Lambda. And now it is a proper grown-up functional language that is Turing complete. Just search for Lambda Excel. Those two keywords will get you lots of raw material.
1:25:04Simon Peyton Jones:Last question for you is, knowing everything that you know now from your career, if you could go back to when you just graduated from college and give yourself some advice, what would you say?
1:25:14Simon Jones:All of these people who you see very successful, wandering around, looking as if they've made it, I guess you might class me among them now. They are, all of them, just making it up as they go along. They feel insecure, uncertain, not sure what to do next, not sure what their next steps are, not sure what next big problem they're going to tackle, unsure about whether they're what doing is going to be successful or not. And so all of their confidence is, I mean, they project confidence, maybe. That's partly a life skill. But often they're not. And so the fact that, you know, in those days, of course, I felt very not confident.
1:25:53Simon Jones:I would say, you know, since all of these successful people are making it up as they go along, it's fine for you to be as well. And they've been lucky, moreover. They've been lucky. they've had but if you want to be lucky you do need to put yourself in a position where accidents can happen to you and that means taking risks so if you want to be lucky you need to put yourself in positions where lucky things could happen and that means taking some kind of risk, so if you're very conservative never take any risks, it's very unlikely that the accident that is life transforming will happen that's a balance of course um but it means an accident are not so bad and of course i'm dying is bad but lots of accidents may change your life in in in a way that might be surprising to you but turns out to be not so bad in retrospect awesome well yeah thank you so much for your time i really appreciate it professor jones we will have a nice talk to you thanks ryan hey thank you for watching
1:26:57Simon Peyton Jones:this podcast if you liked it and you want to see the show grow please support with a comment or a like. Also, if you have any recommendations for people you want me to bring on, please drop a comment. Guests like Barbara Liskov, Mike Stonebreaker, Mark Brooker, these were all people that I brought on because someone left a comment. On another note, aside from the podcast, I'm working on building the ergonomic keyboard that I wish existed. Here's a glance at the prototype. It's a split keyboard, so there's two sides. This is in the case. But yeah, we launched on Kickstarter and we hit our goal within eight hours of launching.
1:27:32Simon Peyton Jones:I really appreciate it if you were one of the people who grabbed one of the early units. We're now working on the long journey of building the tooling now. And so if you still want to pick one up, I've left the late pledges open on Kickstarter. So you can grab one there. I'll put a link in the description. Thank you again for watching the podcast and I'll see you in the next episode.
From the publisher
Simon Peyton Jones is the co-creator of Haskell (pure functional programming language) and I interviewed him about functional programming, why it matters, and his thoughts on other programming languages.
• My ergonomic keyboard project I mentioned, you can follow along here: https://read.compose.llc/
Podcast links:
• YouTube: https://youtu.be/xcB_LF3cdqw
• Apple: https://podcasts.apple.com/us/podcast/the-peterman-pod/id1777363835
• Transcript: https://www.developing.dev/p/co-creator-of-haskell-functional
Thank you to this episode's sponsor for supporting my work:
• WorkOS: makes your app Enterprise Ready with easy to use APIs to add SSO, SCIM, RBAC, and more in just a few lines of code, check them out at https://workos.com/
Timestamps:
(00:00) Intro
(00:39) What functional programming is
(09:18) Downsides of functional programming
(10:53) Specialized hardware for functional programming
(21:47) Haskell is useless
(25:59) Rust vs C
(28:26) Haskell vs OCaml
(35:26) Side effects in Haskell
(44:26) Type systems
(57:30) How the Haskell compiler works
(01:04:35) Why Haskell is talked about more than used
(01:09:07) Avoiding success at all costs
(01:11:12) LLMs and programming languages
(01:13:57) New programming language design
(01:15:59) Should students continue to learn programming
(01:22:33) Why Excel is is 2nd favorite programming language
(01:25:04) Advice for his younger self
Where to find Simon:
• LinkedIn: https://www.linkedin.com/in/simonpj/
• Wikipedia: https://en.wikipedia.org/wiki/Simon_Peyton_Jones
• Personal Website: https://simon.peytonjones.org/
Where to find Ryan:
• Newsletter: https://www.developing.dev/
• X/Twitter: https://x.com/ryanlpeterman
• LinkedIn: https://www.linkedin.com/in/ryanlpeterman/
• Threads: https://www.threads.com/@ryanlpeterman
• Instagram: https://www.instagram.com/ryanlpeterman
• TikTok: https://www.tiktok.com/@ryanlpeterman
Referenced in this episode:
• Haskell is useless: https://www.youtube.com/watch?v=iSmkqocn0oQ
• John Backus Turing Award lecture: https://worrydream.com/refs/Backus_1978_-_Can_Programming_Be_Liberated_from_the_von_Neumann_Style.pdf
• Why functional programming matters: https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf
• Excel is his 2nd favorite programming language: https://www.youtube.com/watch?v=_M4P5M85KO8




