A Very Subjective History of Functional Programming
From Problem to Language: The OriginThe language that became the symbol of academic programming came 2026-7-2 21:45:46 Author: hackernoon.com(查看原文) 阅读量:6 收藏

From Problem to Language: The Origin

The language that became the symbol of academic programming came about because an engineer lacked the right tool for a specific task.

In 1958, John McCarthy was working on a problem that sounds simple today: write a program capable of symbolically differentiating mathematical expressions. Not numerically — not "compute the derivative at the point x=3" — but symbolically: take an expression like x² + 2x and produce 2x + 2. The task required treating the structure of the expression itself as data.

Fortran was not up to it. It had been built for numerical computation: numbers, arrays, loops. The notions of "list", "tree", and "recursive structure" simply did not exist in it. McCarthy was not criticizing Fortran — he had simply encountered a problem of a different kind and set about building a new tool.

That is how LISP came to be. Its central idea emerged almost by accident: to describe the language in an academic paper, McCarthy created an eval function that took a program's source code, written as an ordinary data list. His student Steve Russell translated that formula into assembly language — and LISP suddenly had a working interpreter. Program and data acquired the same structure. The expression (+ x 2) became simultaneously a call to the addition function and a list of three elements. Along the way, it was also necessary to invent the garbage collector: dynamic list structures did not fit into statically allocated memory.

LISP was not an attempt to implement a mathematical theory. McCarthy had encountered Church's λ-calculus, but by his own account had not studied it deeply at the time he created the language. LISP grew out of engineering necessity — and that is important to remember: functional programming did not begin with a theory that someone decided to realize; it began with a problem that needed to be solved.

A Mathematician Looks at Algol

Peter Landin invented syntactic sugar, the virtual machine, and Python's syntax — and still remains one of the most unjustly forgotten names in the history of programming languages.

In the early 1960s, Peter Landin made an observation that looked like a technical footnote but turned out to be a discovery. Algol 60 allowed procedures to be defined inside other procedures. And here an interesting question arose: an inner procedure could use variables from the outer one. What happens to those variables when the outer procedure returns? The stack no longer holds them — yet they are needed. Landin solved this problem by introducing the concept of a closure: a function carries with it the environment in which it was defined. That solution went into every modern programming language — under the same name.

But something else mattered more. Backus and Naur had introduced a formal definition for Algol's syntax, yet its semantics remained poorly formalized. Landin, in attempting to formalize Algol’s semantics, showed that behind it lay a precise mathematical structure — Church's lambda-calculus. Procedures, parameter passing, nested definitions — all of it admitted a rigorous description in terms that mathematicians had developed long before computers existed. Several things grew out of this observation. The SECD machine — an abstract executor that precisely describes how a program is evaluated, a precursor to the idea of a virtual machine. Syntactic sugar — Landin coined the term himself: convenient syntactic constructs that add no expressive power to the language but make it readable.

And the offside rule — also his idea: the nesting level of a block is determined by indentation, not by brackets. Today, this is called "Python's syntax" — and the idea appeared four years before the C language, in which Python is implemented, was even created.

This was a bridge. On one bank — engineers writing programs. On the other — mathematicians have a ready-made apparatus: function theory, formal systems, precise definitions. Landin showed that the bridge was possible. And mathematicians, being enthusiastic people, crossed it with considerable excitement.

Mathematicians Saw a Field of Opportunity

In the 1970s, programming suddenly became interesting to mathematicians — not as a tool, but as an object of study. And they could not hold back.

Once it became clear that a program is a mathematical object rather than merely an instruction for a machine, a genuine research boom began. Programming turned out to be not a craft that mathematicians condescended to examine, but a living field with open questions, elegant structures, and unsolved problems.

There were several directions, and they developed in parallel. Christopher Strachey and Dana Scott laid the foundations of denotational semantics — a rigorous mathematical way to describe what a program means, not only how it executes. Robin Milner developed a type inference system: the compiler determines the type of every expression on its own, without explicit annotations — and does so provably correctly. This became the foundation of ML (1973) and all its descendants.

At the same time, in Edinburgh, John Darlington carried out a quiet revolution in syntax: he replaced unwieldy branching constructs with a system of equations, making it possible to write functions the way mathematicians write them in notebooks (like fib 0 = 1). Tony Hoare and Edsger Dijkstra turned to verification: how to prove that a program is correct — not test it, but prove it, the way one proves a theorem.

The languages of this period were not built for industry — they were research instruments. SASL, ML, Hope, and later David Turner's Miranda — each of them tested some idea: can one do without assignment, what does lazy evaluation give, what does a language with algebraic types look like? Universities became laboratories, and programming languages became experimental apparatus.

It was a happy period: the field was new, the questions were foundational, and no one had yet gotten around to demanding industrial reliability or performance.

The Father of Fortran Takes the Floor

In 1977, the man who created imperative programming walked on stage with a Turing Award in his hands and said: we have gone the wrong way.

In 1977, John Backus received the Turing Award — the highest distinction in Computer Science. By tradition, the laureate delivers a keynote address. Backus delivered his. And said roughly the following: imperative programming is a dead end. The languages we have been building for decades, Fortran included, have inherited a fundamental flaw: they are bound to the von Neumann architecture.

A program is a stream of commands, variables are memory cells, and assignment is the primary tool. He called this the "von Neumann bottleneck": the processor and memory exchange data over a single wire, and the entire culture of programming has been built around that constraint.

The future, in Backus's view, lay with functional programming. Not because it was beautiful — but because programs without assignment and side effects admit mathematical reasoning: they can be transformed, optimized, and their properties proven. He proposed his own language — FP — which never became popular. But the lecture became famous. It was titled "Can Programming Be Liberated from the von Neumann Style?" — and that title alone articulated the question that had been hanging in the air, yet which no one had dared to pose so directly.

The moment was symbolic. The man who created Fortran and, in doing so, set the imperative tradition for decades to come publicly questioned that tradition. The academic researchers working on functional languages in universities gained an unexpected ally — with a Turing Award in his hands.

Languages Grow Up

Haskell was not created in a single laboratory — it was designed by a committee from several universities who simply agreed to cooperate. That rarely happens in the history of programming languages.

In the 1980s and 1990s, what happens to any idea that is ahead of its time finally happened: reality caught up with theory. Computers became fast enough that a garbage collector no longer seemed an unaffordable luxury, and lazy evaluation no longer a performance disaster. Functional languages ceased to be slow by definition.

At the same time, a critical mass of theoretical results had accumulated. Milner's type inference worked. Algebraic data types offered expressiveness unattainable in imperative languages. Lazy evaluation opened the possibility of working with infinite data structures — elegantly and correctly. All of this was asking to be unified in a single language.

In 1987, a committee of researchers from several universities solved this problem radically — by agreeing. The academic language market was dominated by the lazy but proprietary Miranda, and researchers needed an open, shared standard. In 1990, Haskell appeared — lazy, purely functional, with polymorphic typing and type inference. Not the tool of a single research group, but an attempt to codify the best of what had been accumulated.

The committee had planned simply to consolidate existing work, but ventured one bold experiment — adding type classes to the language. This concept solved the problem of operator overloading (for example, how to add both numbers and matrices with a single function) and gave the rigorous Haskell a flexibility comparable to dynamic languages. A tool had appeared on which one could not only test ideas, but write serious programs.

Functional languages have grown up. The next question was inevitable: what does industry make of all this?

Ideas Cross the Border

Programmers, mathematicians, and language designers never lived in complete isolation. Ideas travelled — through papers, conferences, and people who had one foot in academia and one in industry.

Once functional ideas had proven their viability, they began appearing in places where nobody had formally invited them.

C++ gained the STL — a library built around generic algorithms: transforming collections, filtering, and folding. Its author, Alexander Stepanov, spoke openly about the influence of functional programming. When he was designing std::accumulate, he was not trying to satisfy mathematicians — he simply took the concept of a fold and gave it a shape that systems programmers could understand. Functional programming had taken root inside the most uncompromising systems language in the industry.

Java 8 gained lambdas and streams. Python received list comprehensions — a construct whose syntax had been refined in the lazy languages of the 1980s. JavaScript acquired map, filter, reduce. Languages that had never declared themselves functional were, one after another, adding tools from the functional tradition.

The reason was simple: these tools worked. Code became shorter, intent was expressed more precisely, and an entire class of errors disappeared — a function without side effects simply cannot spring a surprise: the same call always produces the same result. The paradigm was ceasing to be a matter of conviction and becoming a matter of convenience.

The boundary between functional and imperative programming began to blur — not as the result of one side's victory over the other, but because developers pragmatically took the best from both worlds.

A World of Mixed Paradigms

In the mid-2000s, physics put an end to the growth of processor clock speeds — and inadvertently turned immutability from academic elegance into a practical necessity.

Today, the question "Is this language functional or imperative?" has almost lost its meaning. Scala combines object-oriented and functional programming so organically that drawing a boundary is impossible. Kotlin, Swift, and Rust carry algebraic data types, pattern matching, and immutability by default — and yet nobody calls them functional languages. F# lives on the .NET platform and, at the same time, is a direct descendant of ML. Python allows code to be written in any style — and programmers mix styles within a single file without giving it a second thought.

There was also a technical trigger that accelerated this process. In the mid-2000s, processor clock speeds stopped growing — physics would not allow it. Manufacturers began adding cores. This made mutable shared state a visible engineering problem: when multiple threads simultaneously modify the same data, bugs become unpredictable and hard to reproduce. Immutability and pure functions were transformed from academic elegance into a practical tool for fighting concurrency bugs.

The paradigms did not defeat each other. They blended together — and that is a good thing.

Why This Matters

The concepts of functional programming are already everywhere. Usually — with no explanation of where they came from or why they are structured the way they are.

The history we have just traced ends with a simple observation: the concepts of functional programming are found everywhere today. Lambdas, immutability, algebraic types, pattern matching, and higher-order functions — all of this has long since left Haskell and university curricula behind. Knowledge of these concepts has ceased to be a specialization and has become part of a developer's general literacy — much as knowledge of data structures or algorithms has.

The difference is that data structures are usually explained. Functional concepts, more often than not, are simply used — with no explanation of where they come from, why they are structured the way they are, or what lies behind them.

The story that began with McCarthy needing a tool to differentiate an expression, passed through Landin's observation about Algol, through the research boom of the 1970s, through Backus's provocation, through the maturation of Haskell — and ended up inside every language you use today. This journey is worth knowing.


文章来源: https://hackernoon.com/a-very-subjective-history-of-functional-programming?source=rss
如有侵权请联系:admin#unsafe.sh