Hasty Briefsbeta

Bilingual

7 lines of code, 3 minutes: Implement a programming language (2010)

6 hours ago
  • #lambda-calculus
  • #interpreter
  • #programming-languages
  • The lambda calculus is a minimalist, higher-order functional programming language known as the lambda calculus.
  • The lambda calculus lives at the core of major functional languages like Haskell, Scheme, and ML, and also exists within JavaScript, Python, and Ruby.
  • Alonzo Church developed the lambda calculus in 1929, before computers existed, as a mathematical notation for reasoning about functions.
  • Alan Turing defined the Turing machine, which became the first accepted definition of a general-purpose computer, and it was soon discovered that the lambda calculus and the Turing machine were equivalent.
  • The lambda calculus has only three kinds of expressions: variable references, anonymous functions (lambda terms), and function calls.
  • Anonymous functions are written with a 'λ-dot' notation, e.g., '(λ v . e)' is the function that accepts an argument 'v' and returns the value of 'e'.
  • Function calls are written by putting two expressions adjacent, e.g., '(f e)'.
  • The lambda calculus achieves Turing-equivalence through two of the coolest programming hacks out there: Church encodings and the Y combinator.
  • A 7-line, 3-minute interpreter for the lambda calculus in R৫RS Scheme demonstrates an environment-based denotational interpreter.
  • The interpreter uses two core functions: 'eval' and 'apply', with conceptual signatures: 'eval : Expression * Environment -> Value' and 'apply : Value * Value -> Value'.
  • Racket provides a match construct that cleans up the interpreter, making it cleaner and easier to understand.
  • The eval/apply design of the interpreter scales to much bigger languages; for example, in about 100 lines we can implement an interpreter for a sizable subset of Scheme itself.
  • We can add various expression forms (variables, constants, primitives, conditionals, bindings, mutation, sequencing) and top-level forms (function definition, global definition) to the language.
  • The entire interpreter, with test harness and test cases, fits in a concise implementation.
  • Modifying the last interpreter allows quickly testing out new ideas for programming languages by separating syntactic design from semantic design.