Unit 1. Foundations of functional programming

There are two major ways to understand the act of programming. The first, and historically more common, is the view that the programmer provides a sequence of instructions to a computer in order to make it behave a certain way. This model of programming ties the programmer to the design of a particular tool for programming, namely a computer. In this type of programming, the computer is a device that takes input, accesses memory, sends instructions to a processing unit, and finally delivers output to the user. This model of a computer is called von Neumann architecture, after the famous mathematician and physicist John von Neumann.

The programming language that best embodies this way of thinking about programs is C. A C program takes in data from the standard input controlled by the operating system, stores and retrieves necessary values in physical memory that frequently must be manually managed, requires the handling of pointers to a specific block of memory, and finally returns all output through the standard output controlled by the OS. When writing C programs, programmers must understand as much about the problem at hand as the physical architecture of the computer in front of them.

But a computer built with von Neumann architecture isn’t the only way to perform computation. Humans perform a wide variety of computations that have nothing to do with thinking of memory allocation and instruction sets: sorting books on a shelf, solving a derivative of a function in calculus, giving directions to friends, and so forth. When we write C code, we’re programming to a specific implementation of computation. John Backus, who led the team that created Fortran, asked in his Turing Award lecture, “Can programming be liberated from the von Neumann style?”

This question leads to the second way to understand programming, which is the subject of the first unit in this book. Functional programming attempts to liberate programming from the von Neumann style. The foundations of functional programming are abstract, mathematical notions of computation that transcend a specific implementation. This leads to a method of programming that often solves problems simply by describing them. By focusing on computation, not computers, functional programming allows the programmer access to powerful abstractions that can make many challenging problems much easier to solve.

The price of this is that getting started can be much more difficult. Ideas in functional programming are often abstract, and we must start by building the idea of programming up from first principles. Many concepts need to be learned before we can build useful programs. When working through this first unit, remember that you’re learning to program in a way that transcends programming a computer.

Just as C is the nearly perfect embodiment of the von Neumann style of programming, Haskell is the purest functional programming language you can learn. As a language, Haskell commits fully to Backus’s dream and doesn’t allow you to stray back to more-familiar styles of programming. This makes learning Haskell more difficult than many other languages, but learning Haskell makes it impossible for you to not gain deep insights into functional programming as you go. By the end of this unit, you’ll have a strong enough foundation in functional programming to understand the basics of all other functional programming languages, as well as being prepared for your journey to learn Haskell.