I talked a little bit about the history of the language. Scheme is a direct descendant of Lisp. Lisp was invented by John McCarthy in 1958. Unlike many of the early computing pioneers, McCarthy was more interested in symbolic computation than in numeric computation. He became a pioneer in the field of artificial intelligence research and Lisp became the dominant programming language among AI researchers. Our senior AI course (cse473) lists cse341 as a prerequisite because of this long history of using functional languages like Scheme for AI.
One thing that people like about Lisp and Scheme is that they are very simple languages. They do not have a lot of syntax or special rules to memorize. This was even more true of Lisp than it is of Scheme, but Lisp was too simple. It led to many different flavors of Lisp and made it difficult to execute the same Lisp program on different systems. Two major variations have emerged as the dominant players: Common Lisp and Scheme.
Scheme got a significant boost in the 1980's when Hal Abelson and Jerry Sussman published the textbook they were using in the introductory computer science class at MIT. The book is titled Structure and Interpretation of Computer Programs, also known as the wizard book or SICP. It is one of the best books ever written about computer science. A lot of schools tried using it as an intro book, but that movement has slowly lost steam over time. Still, the book is a great resource. It is available online and I have included links to the book and to Abelson and Sussman's lectures from the "Scheme resources" link of our class page.
We spent most of the rest of the lecture time looking at how the Scheme interpreter evaluates various expressions. We are using the DrScheme environment that will run on most platforms. It should be available on the machines in the CSE labs. You can install it on your own computer. When it first executes, it will ask you which language you want to use. Select "PLT" and "Pretty Big".
We saw that numbers evaluate to themselves, as in:
> 3.8 3.8 > 42 42There are special symbols that represent true and false that also evaluate to themselves:
> #t #t > #f #fJust as in ML, there are some predefined functions available at the top level:
> length #<primitive:length> > abs #<primitive:abs>Scheme calls these procedures rather than functions (I'm likely to use both words because I'm more used to calling these functions). The two listed above are for the absolute value of a number and the length of a list.
In addition to symbols, Scheme has lists of values enclosed in parentheses. To call a procedure, you put its name as the first value in the list. For example, we can add two numbers by saying:
> (+ 3 4) 7These expressions can be nested, so we can ask for 2 times the sum of 8 and 12 by saying:
> (* 2 (+ 8 12)) 40If you want to define a variable to have a value, you can call the define procedure:
> (define x 3.4) > x 3.4After this definition, you can use x in expressions, as in:
> (define y (+ x 3)) > y 6.4One of the things that takes a while for beginners to get used to is figuring out when Scheme evaluates something and when it does not. For example, you can define one symbol to be bound to another symbol, but not by saying:
> (define z x) > z 3.4Scheme binds z to the value of x rather that binding it to the symbol x (if not, our previous example would not have worked out). So we often need to make a call on quote:
> (define z (quote x)) > z xThis can be abbreviated with the single quotation mark:
> (define z 'x) > z xUsing the quote, we can also bind variables to lists:
> (define a '(1 2 3 4)) > a (1 2 3 4)We then saw that the ML functions hd and tl have counterparts in the Scheme procedures first and rest:
> (first a) 1 > (rest a) (2 3 4)But most people use the procedures car and cdr (pronounced "kar" and "cou-der") that have been part of Lisp since the beginning:
> (car a) 1 > (cdr a) (2 3 4)There are abbreviations for things like the car of cdr of the cdr of the cdr:
> (car (cdr (cdr (cdr a)))) 4 > (cadddr a) 4This is pronounced "ka-dih-dih-der." If you don't want to struggle with pronunciation, you can use the simpler name "fourth":
> (fourth a) 4We saw that the procedure cons is the equivalent of the ML :: operator:
> (cons 'a ()) (a) > (cons 'a (cons 'b ())) (a b)We had to use quotes here because Scheme evaluates each of the arguments passed to the cons procedure.
I pointed out that define is considered a special form because it does not evaluate its first argument (the variable being defined does not need to be quoted).
We define procedures in Scheme with the following syntax:
(define (double n) (* 2 n))We tend to read this as, "Define double of n to be the times of 2 and n."
In ML we had an if/else construct. ML uses keywords to separate the different parts:
> (if (< 3 4) "hello" "there") "hello"We put these pieces together to define a factorial procedure. I defined it in the edit window rather than in the interpreter:
(define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1)))))We then clicked on the "Run" button to go back to the interpreter with this definition loaded. We could then run it with various values:
> (factorial 3) 6 > (factorial 5) 120I also pointed out that Scheme supports arbitrary length integers, as in:
> (factorial 50) 30414093201713378043612608166064768844377641568960512000000000000