← back to programming

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.

complex real rational integer raise each type can be raised to the next

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.

Scheme

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.

Scheme

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.

Scheme

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.

Scheme

Notation reference

Scheme Python Meaning
(add x y)add(x, y) / x + yGeneric addition
(apply-generic op . args)apply_generic(op, *args)Dispatch on all argument types
(put-coercion from to proc)coercion[(from, to)] = fnRegister 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 + p2Add 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

Category theory connections

  • ๐Ÿž Milewski Ch.4 โ€” Kleisli categories: type lifting via monadic bind is the categorical version of coercion

Foundations (Wikipedia)

Ready for the real thing? Read SICP §2.5.