SCHEME NAMING There are several naming conventions in Scheme that you should know and attempt to adhere to. Unfortunately, there's really a lot if irregularity, especially in many application programs. One important irregularity is that list operations often have inscrutable names (e.g. car, cons) that come from LISP. List operations also typically don't have "list" in their names to tell you they're operations on lists---lists are so common that they're sort of the default data type for non-arithmetic expressions. (Arithmetic expressions are different, in that they're typically generic---they work for all different kinds of numbers.) NAMES MAY CONTAIN FUNNY CHARACTERS Identifiers (names of non-literals) in Scheme generally start with an alphabetic character, but can contain digits and other non-alpha characters. foo!, bleen23, fooX<, quux?fail, and how-is-first-patient-doing-since-last-injection? are all legitimate identifiers in Scheme. HYPHENS ARE THE USUAL SEPARATOR Scheme programmers often give variables and procedures fairly long, descriptive names, where the pieces of the name are glued together with hyphens. So for example, initialize-xwindows-interface. NAMES MAY BE LONG This is especially true for functions whose use is tricky, e.g., process-non-null-input-record, where the name tips you off that you're using the wrong function if the argument is null. Programmers are likely to give things long names if they're not used in many places, but shorter names if they must be used frequently in lots of places. PREDICATES END IN ? Little routines that check to see if some property is true are usually given a name that ends in a question mark. These routines usually return #f if the property is not true, but may return any other value if the property is true. (For example, the empty list may be a useful value, and counts as true when used in a conditional.) DESTRUCTIVE OPERATIONS END IN ! Operations that modify the state of their arguments are often typically names that end in an exclamation point. So, for example, the normal reverse routine does not modify the list it is given as an argument, but one that does modify the list (reversing the items in the same actual list of cons cells) would be called reverse! FIELD UPDATE OPERATIONS START (OR SOMETIMES END) WITH SET Operations to update field values often include the word set-, for example set-car! and set-cdr!, which update the fields of a pair, and vector-set!, which updates an element of a vector. Typically, set- is followed by the name of the field to update, as in set-car! and set-cdr!. In the case of vectors, that's left out because the fields of a vector don't really have names, just indices. OPERATIONS ON MANY KINDS OF DATA STRUCTURES ARE OFTEN PREFIXED WITH THE NAME OF THE DATA STRUCTURE Names of routines that operate on particular data structures are often prefixed with the name of that data structure, e.g. vector-set!, vector-ref, string-set!, string-ref. Note that if you combine this with the previous rule, you might have operations on points to set and get their x and y values named point-set-x!, point-x-ref, point-set-y! and point-get-y!. ----------------------------------------------------------------------- SCHEME INDENTATION In Scheme and Lisp, indentation is very important. Since the language has very little syntax, it is easy to write completely unreadable code; it is ABSOLUTELY ESSENTIAL that you use proper indenting to show the structure of the program. There are some very well-established traditions for indenting Lisp and Scheme---get used to them. For any class where I teach Scheme, the following rules are NOT optional. Programs written without proper indenting may get MANY points taken off. One technological note: if you don't have an editor that matches parentheses, get one. Most editors (even vi) have some feature that will tell you which right parenthesis matches a given left parenthesis, or vice versa. This is extremely handy in telling whether you've typed enough parentheses to close an expression---or too many, and you're closing an outer expression you didn't mean to. A good editor (like emacs) will have a Lisp mode (or better, a Scheme mode) that will help do indenting for you automatically and/or reformat your code according to reasonable indentation conventions. It's a good idea to use such an editor, but at the bare minimum get to know your parenthesis-matching feature of your favorite editor. It is common for very short expressions to be written out on a single line, rather than indented. So we might write (if a b c) rather than (if a b c) or we might write (define (double x) (+ x x)) rather than (define (double x) (+ x x) Try to exercise judgement about this. Some people will only spread things across multiple lines and indent them when the expression literally will not fit on a line. That's bad---you WANT to break things up and indent them to help people read them by showing levels of nesting, etc. INDENTING PROCEDURE CALLS for simple procedure call expressions, (proc arg1 arg2 ... argn) will work. For more complex ones, where the args are complex expressions or have long names, something like (proc arg1 arg2 arg3) INDENTING IF In an if statement, all of the operands should be to the right of the keyword IF, e.g., (if condition-expression consequent-expression alternative-expression) Notice that I've lined up all three of the subexpressions. This is the usual way of doing things, and I'd rather you do it that way too. A drawback is that it looks like a procedure call. Another possible indenting convention is (if condition-expression consequent-expression alternative-expression) Note that in this case the consequent and the alternative ARE lined up, because they fill similar roles. They aren't lined up exactly under the condition expression, because they DON'T have a similar role. The advantage here is that the similarities and differences of the roles of the subexpression are reflected in the layout. Unfortunately, this isn't the usual way of doing it, and there's a big advantage to doing things the usual way---your ifs won't look like ifs to most people. INDENTING COND COND is indented like a procedure call or if at the top level of structure, i.e., (cond condition-action-clause1 condition-action-clause2 ... condition-action-clausen) Each condition-action clause is a two-element pair listing a condition and an action to be taken if the condition is true. If both the condition and the action are small expressions, they can both go on one line, thus: (cond (condition1 action1) (condition2 action2) ... (conditionn actionn)) If the conditions and/or actions are large expressions, then the condition-action pair is split and the action is lined up DIRECTLY UNDER the condition it goes with, thus: (cond (big-hairy-condition-expression1 big-hairy-action-expression1) (big-hairy-condition-expresssion2 action-expression2) ... (condition-expressionn big-hairy-action-expressionn)) Note that some of these pairs are small enough they might fit on one line comfortably, but I broke them all the same way anyway. That's generally the right thing to do, because it's harder to visually parse something that is formatted in different ways in different places at the same level of structure. This is particularly important for COND because it's hard to parse visually anyway---the only indenting you get is the one character where the left parenthesis sticks out at the beginning of a condition-action pair. This one-character difference between conditions and actions is really not enough, but that's the standard way of doing it, so you should do it that way. Don't make it worse by formatting inconsistently within a single COND. INDENTING LET LETs should be indented in a way that shows that the variable binding clauses are different from the expressions in the body. It's usually a good idea to line the variable binding clauses up vertically, and then go back to the left a bit, so that the expressions in the body are indented about 3 characters. (I strongly prefer exactly three characters), e.g., (let ((var1 init1) (var2 init2) ... (varn initn)) body-expr1 body-expr2 ... body-exprn) Notice that this makes a notch where the variable binding clauses are indented 6 characters, and then the body statements come half-way back to the left. This notch is very distinctive and makes lets very recognizable. DON'T INDENT THE BODY AS FAR AS THE VARIBLE BINDING CLAUSES. You want that notch to tip you off that this is a binding contour. INDENTING NAMED LETS Named lets should be indented pretty much like normal lets, except that the let name will push the variable binding list over to the right, e.g.: (let loop ((var1 init1) (var2 init2)) body-expr1 body-expr2)) INDENTING LAMBDA Like LETs, lambdaS should be indented so that the body looks different from the variable binding list, e.g., (lambda (var1 var2 ... varn) body-expr1 body-expr2 ... body-exprn) You usually won't have to break the variable list up, because it's just a few symbols, but if you have a function of many arguments with long names, line them up vertically like the binding clauses in a let: (lambda (long-variable-name1 long-variable-name2 ... really-long-variable-name3) body-expr1 body-expr2 ... body-exprn) INDENTING DEFINES For defines using the normal variable-definition syntax (as opposed to the sugared procedure definition syntax), you should line up the value clause with the name, e.g.: (define varname initial-value-expression) It is very common for simple defines to fit on one line, however, e.g., (define my-flag #f) or (define value (compute-initial-value)) or (define identity-function (lambda (x) x)) Defines using the sugared procedure-defining syntax should look pretty much like a lambda, e.g., (define (procname arg1 arg2 ... argn) body-expr1 body-expr2 ... body-exprn)) Note that the body expressions are only indented a few characters from the start of the define. They are NOT lined up under the procedure name. SPECIAL CASES For forms not described here, the best thing to do is to look at some well-formatted code and use that as an example. Failing that, use your best judgement (e.g., a CASE is a lot like a COND, so it should probably look similar). In some cases, you may want to avoid indenting quite as much as the examples above, to avoid having things run off the right side of the page. Sometimes people use special indenting rules in such cases, for example putting a keyword like COND on its own line, and indenting all of the condition-action pairs just a tiny bit from that: (cond ((condition expression... (action expression... ((condition expression... (action expression...))) Note that this makes things much harder to read (especially when you nest a bunch of things like this, so it's just a gently sloping jumble). In such cases, it's often best to extract some of the code and put it in a helper procedure. The fact that the usual indenting rules are causing you trouble is often a sign that you're not breaking your code into the right procedures. (It can also be a sign that you're using really long variable names, which may be a good idea despite this problem.)