Generic Operations
Abelson & Sussman ยท 1996 ยท SICP ยง2.5
A generic arithmetic system that works across number types. Coercion and type towers let you add a rational to a complex number without either type knowing about the other. The dispatch table from Chapter 7 scales to an entire algebra.
Generic arithmetic operations
We want (add x y) to work whether x and y are ordinary numbers, rationals, or complex. Each number type installs its own add, mul, etc. in the dispatch table. The generic operations look up the types and delegate.
Combining data of different types
What about (add 3 1/4)? The types don't match. Coercion converts one type to the other. A coercion table maps (from-type, to-type) to a conversion function. When apply-generic finds no direct match, it tries coercing one argument to the other's type.
Type towers and hierarchies
Types form a tower: integer < rational < real < complex. Each type can be "raised" to the next level. When types don't match, raise the lower one until they do. This is simpler than explicit coercion between every pair: you only need n-1 raise functions instead of n(n-1) coercions.
Polynomial arithmetic
The generic arithmetic system is extensible enough to add polynomials. A polynomial is a variable plus a list of terms. add-poly adds matching terms. Polynomial coefficients can themselves be polynomials (or rationals, or complex numbers), because the coefficient arithmetic uses the same generic add and mul.
Notation reference
| Scheme | Python | Meaning |
|---|---|---|
| (add x y) | add(x, y) / x + y | Generic addition |
| (apply-generic op . args) | apply_generic(op, *args) | Dispatch on all argument types |
| (put-coercion from to proc) | coercion[(from, to)] = fn | Register type conversion |
| (raise x) | raise_value(x, target) | Move up the type tower |
| (make-poly var terms) | Poly(var, terms) | Polynomial constructor |
| (add-poly p1 p2) | p1 + p2 | Add polynomials |
Translation notes
Python's __add__, __mul__ and friends are exactly SICP's generic operations, baked into the language. The dispatch table is the method resolution order (MRO). Coercion is __radd__ and __coerce__ (deprecated but instructive). The type tower is Python's numeric abstract base classes: Integral < Rational < Real < Complex in the numbers module.
The polynomial example shows the real payoff: because polynomial coefficients use the same generic arithmetic, you get polynomials over rationals, polynomials over complex numbers, and even polynomials over polynomials (multivariate) for free. This is the algebraic structure that type classes in Haskell and protocols in Swift formalize.
Neighbors
SICP chapters
- ๐ช Chapter 7 โ Multiple Representations (dispatch tables introduced)
- ๐ช Chapter 9 โ Assignment & State (mutation changes everything)
Category theory connections
- ๐ Milewski Ch.4 โ Kleisli categories: type lifting via monadic bind is the categorical version of coercion
Foundations (Wikipedia)
Type coercion โ implicit conversion between types
Algebraic data type โ the type theory behind tagged unions