Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Chapters 1 and 2 describe the close connection between two fundamental elements of programming: functions to express behavior and data to express information. We saw how functions can be manipulated as data using higher-order functions. We also saw how data can be endowed with behavior using an object system. We have also studied techniques for organizing large programs, such as functional abstraction, data abstraction, and classes. These core concepts constitute a strong foundation upon which to build modular, maintainable, and extensible programs.

This chapter focuses on the third fundamental element of programming: programs themselves. A Python program is just a collection of text. Only through the process of interpretation do we perform any meaningful computation based on that text. A programming language like Python is useful because we can define an interpreter, a program that carries out Python’s evaluation and execution procedures. It is no exaggeration to regard this as the most fundamental idea in programming, that an interpreter, which determines the meaning of expressions in a programming language, is just another program.

Programming Languages

Programming languages vary widely in their syntactic structures, features, and domain of application. Among general purpose programming languages, functions are pervasive. On the other hand, powerful languages exist that do not include an object system, mutation, or even control constructs such as while and for statements. As an example of a powerful language with any of these features, we will introduce the Gleam language.

Learning a new language provides an opportunity to see how much of what you have learned about programming in Python applies more generally. Many concepts are shared by Python and Gleam (and many other languages), such as how names are looked up in environments (called static scoping) and what happens when functions are called.

Learning a new language can also introduce you to new concepts. Gleam is an excellent language for learning about pattern matching and algebraic data types (as in Rust, TypeScript, Swift, and others), value-based error handling (as in Rust, Go, Elm, and others), and working with immutable data (as in Rust, Erlang, Scala, OCaml, Haskell, and others). For readers interested in learning Rust, which has emerged as an immensely popular language for developing performant and reliable applications, first learning Gleam is a natural path.

Interpreters

This chapter also discusses the design of interpreters and the computational processes that they create when executing programs. The prospect of designing an interpreter for a general programming language may seem daunting. After all, interpreters are programs that can carry out any possible computation, depending on their input. However, many interpreters have an elegant common structure: two mutually recursive functions. The first evaluates expressions in environments; the second applies functions to arguments.

These functions are recursive in that they are defined in terms of each other: applying a function requires evaluating the expressions in its body, while evaluating an expression may involve applying one or more functions.

Gleam was chosen in part because its approach to types and pattern matching is well suited to implementing an interpreter.