Scheme is a simple programming language with an extremely regular syntax and a succinct, well-defined semantics.

Computational Class


Programming Paradigms

Defined by


Things written in Scheme


Scheme is often looked at historically, and described as a variant of Lisp. While useful, this historical viewpoint frequently gets in the way of thinking about Scheme's significance today. In brief, if you are evaluating Scheme for your own needs, evaluate Scheme, and don't worry about Lisp or functional programming.

That said, let's go ahead and examine Scheme historically. Its history has been one of shedding baggage from its Lisp heritage: it has lexical (instead of dynamic) scoping, guaranteed (rather than if-your-vendor-supports-it) tail-recursive behaviour at execution time, hygenic (instead of textual) macros, and continuations as first-class objects. These are generally considered significant improvements, and we fully agree.

But there's one thing of Lisp's that Scheme hasn't shed: its syntax... or lack thereof!

Whether you love it or hate it, you have to admit that Scheme's S-expression syntax is extremely — no, pathologically — regular. Just about as orthogonal as syntax can get.

As far as we know, the reason Lisp has such a mind-bogglingly minimal syntax is that it's a consequence of how it approached higher-order functions: represent functions as lists. You can already pass lists to and return lists from functions, so if functions "are" lists, then problem solved, right? And there's no sense having two different syntaxes for the same kind of data.

But that didn't turn out too happily, and times have changed. In Scheme, function values are not lists: they're closures. This is overall a nice thing — it avoids the ugliness of trying to determine which list is the "right" representation, and allows free variables to be captured in function values instead using the crutch of dynamic binding.

But that syntax is still there, like some kind of vestigial organ. What purpose does it serve now?

Well, the interesting thing about it is that it makes it impossible to syntactically distinguish between code and data. Depending on the circumstance, this can be a horror or a delight.

Here's the horror: say you're looking at a snippet of a Scheme program. You can't tell what (+ 1 2) is supposed to be — code, or data? — without looking at what context it's in. This can be as confusing as all git-out. (And don't get me started on quasiquote.)

Here's the delight: it makes it trivial to read and write Scheme programs from other Scheme programs. No parsing, no backpatching. No blood, sweat, or tears. In fact, we wonder why this holdover from Lisp has not driven Scheme on to become the program-analysis language.