Let us contrast a program written in Scheme with one written in C. Here is the Scheme equivalent of the program we developed earlier. Note that the only real difference is that the parentheses are placed a little differently, and the commas have been removed:
(define (in-list? i sl) (if (empty? sl) false (if (equal? i (first sl)) true (in-list? i (rest sl)))))This program can be tested immediately with a few examples (again notice how similar these look to the examples we wrote before):
(in-list? "cheese" empty) (in-list? "cheese" (put "cheese" empty)) (in-list? "cheese" (put "apples" (put "cheese" empty))) (in-list? "cake" (put "apples" (put "cheese" empty)))When these are entered into the Scheme environment, it responds with
true
or false
, as appropriate.
In contrast, here is the same program in C. The portions highlighted in red are the parts which add no intellectual value to the program; they are merely artifacts of C's technology which must be explained before the student can write this program.
#include <stdio.h> typedef struct shoppingListElement * shoppingList; typedef char * shoppingItem; typedef struct shoppingListElement { shoppingItem item; shoppingItem rest; } int in_list (shoppingItem i, shoppingList sl) { if (NULL == sl) return 0; else if (i == (sl -> item)) return 1; else return (in_list (i, sl -> rest)); }There are more complications. The portions in purple (
==
) require special care;
using =
instead will make the program produce wildly
different output. (This trap is sprung even on professional C
programmers with annoying regularity.) Finally, the orange portions (->
), which are
pointer dereferences, hide a nasty truth: C does not check whether the
pointer is valid and, even if it is, whether there is in fact such a
field in the object pointed to. If there is an error, the system may
never signal it, instead letting the program run for millions of
instructions, often to produce an answer (which, insidiously, may be
close enough to the right answer that the programmer may never know
the program is wrong, only to have it crash on a later run).
But this is only half the problem! Even after writing this code, the student is nowhere near testing it. That requires another block of code:
void main () { shoppingItem i1 = "cheese"; shoppingItem i2 = "coke"; shoppingList l0, l1, l2; l0 = NULL; l1 = (shoppingList) malloc (sizeof (shoppingList)); l1 -> item = "cheese"; l1 -> rest = l0; l2 = (shoppingList) malloc (sizeof (shoppingList)); l2 -> item = "apples"; l2 -> rest = l1; printf ("%d\n", in_list (i1, l0)); printf ("%d\n", in_list (i1, l1)); printf ("%d\n", in_list (i1, l2)); printf ("%d\n", in_list (i2, l2)); exit (0); }The student has to write all this code just to test out the function. This code is fraught with even more difficulties, including the need to understand the
malloc
procedure, casts, and formatted
output. In DrScheme, one more test case means just typing the
function application in the Interactions window. In C, it means
editing this program, adding the proper declarations and compiling it
before it can be run.
(Actually, this program has some minor and some major errors, but many compilers don't flag them, and on most systems it produces the right answers. Teachers who use C or C++ may wish to find these errors.)
PLT / scheme@cs.rice.edu
Last modified at 10:49:37 CST on Monday, November 10, 1997