I'll give you a little further explanation. Some of these are not taught in the book. > * it's lack of syntax (code == data - this allows you to write programs > that build and modify programs) Basically, this is the fact that programs are simply lists. (* 2 3) is simply a list of 3 elements. If I happen to send that list to the interpretter, it gets interpretted, but it's valid scheme data, too. I can use this fact to do customized preprocessing on code. We'll get back to this fact in macros. > * closures > Closures are what happen when you create functions at runtime. Let's say you have: (let ( (a 1) (b 2) ) (lambda (x) (* x b)) ) In this case, we are creating a function and returning it. The function has one parameter - x, but it also has full access to the symbol table within it's lexical scope at the time of creation. That means if b is 5 on one invocation and 6 on the next, I will have two separate functions - the code will be the same, but the variable values it has access to will be different. These variables are said to be "closed" over the created procedure. > * continuations I don't know if the book deals w/ continuations or not. Imagine if you had threads, coroutines, try/except blocks, and gotos all packaged within the same function, which was guaranteed to maintain internal consistency (unlike normal gotos). (call-with-current-continuation) is one of the most ingenious functions I've ever seen, but it's only implemented as far as I'm aware in Scheme and ML, although I've been playing around with creating a partial C implementation. > * macros This of C macros - pretty ugly, because they deal entirely on a textual basis. With Scheme, since programs are just list data, Scheme macros can operate on the program structure itself, not just it's texttual representation. This paves the way for enormous flexibility. > * support for lazy evaluation Lazy evaluation is the ability to delay computation until any later time. So, let's say you have an expensive operation, q. You can delay it's application by saying (delay (q x)). This will result in a value that is a suspension - meaning that it hasn't actually run the operation yet. Lets say you did (set! z (delay (q x))). Now, if you want the value, you simply do (force z). The first time, it will run the computation, and every other time it will return the value it had when first forced. This allows you to decouple function execution and data storage - if you end up not using a value, you don't have to spend time computing it. There are languages like SASL and Haskell where the entire language is built on lazy evaluation. With scheme, it's an alternative, but not forced. > * first-class functions You said you already were familiar with this > * first-class symbols With scheme, when you have a symbol like 'hello, doing equality comparisons with symbols (eq? 'hello 'hello) is reduced to a single machine instruction. Many programming books call this "interned" strings. They are used mostly for variable storage and named constants, but have other uses as well. > * strictly-typed but loosely bound The types in Scheme are strict - i.e. - an "int" cannot auto-morph into a string like it can in Perl. However, the variables are not tied to specific types, so they are loosely bound. > Jon It's me again! Jon