If we can form compound data using symbols, we can have lists such as
(a b c d) (23 45 17) ((Norah 12) (Molly 9) (Anna 7) (Lauren 6) (Charlotte 4))Lists containing symbols can look just like the expressions of our language:
(* (+ 23 45) (+ x 9))
(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))
In order to manipulate symbols we need a new element in our language: the ability to quote a data object. Suppose we want to construct the list (a b). We can't accomplish this with (list a b), because this expression constructs a list of the values of a and b rather than the symbols themselves. This issue is well known in the context of natural languages, where words and sentences may be regarded either as semantic entities or as character strings (syntactic entities). The common practice in natural languages is to use quotation marks to indicate that a word or a sentence is to be treated literally as a string of characters. For instance, the first letter of ``John'' is clearly ``J.'' If we tell somebody ``say your name aloud,'' we expect to hear that person's name. However, if we tell somebody ``say `your name' aloud,'' we expect to hear the words ``your name.'' Note that we are forced to nest quotation marks to describe what somebody else might say.
We can follow this same practice to identify lists and symbols that are to be treated as data objects rather than as expressions to be evaluated. However, our format for quoting differs from that of natural languages in that we place a quotation mark (traditionally, the single quote symbol ') only at the beginning of the object to be quoted. We can get away with this in Scheme syntax because we rely on blanks and parentheses to delimit objects. Thus, the meaning of the single quote character is to quote the next object.
Now we can distinguish between symbols and their values:
(define a 1)
(define b 2)
(list a b) (1 2)
(list 'a 'b) (a b)
(list 'a b) (a 2)
Quotation also allows us to type in compound objects, using the conventional printed representation for lists:
(car '(a b c)) aIn keeping with this, we can obtain the empty list by evaluating '(), and thus dispense with the variable nil.
(cdr '(a b c)) (b c)
One additional primitive used in manipulating symbols is eq?, which takes two symbols as arguments and tests whether they are the same. Using eq?, we can implement a useful procedure called memq. This takes two arguments, a symbol and a list. If the symbol is not contained in the list (i.e., is not eq? to any item in the list), then memq returns false. Otherwise, it returns the sublist of the list beginning with the first occurrence of the symbol:
(define (memq item x) (cond ((null? x) false) ((eq? item (car x)) x) (else (memq item (cdr x)))))For example, the value of
(memq 'apple '(pear banana prune))is false, whereas the value of
(memq 'apple '(x (apple sauce) y apple pear))is (apple pear).
Exercise. What would the interpreter print in response to evaluating each of the following expressions?
(list 'a 'b 'c)
(list (list 'george)) (cdr '((x1 x2) (y1 y2)))
(cadr '((x1 x2) (y1 y2))) (pair? (car '(a short list))) (memq 'red '((red shoes) (blue socks)))
(memq 'red '(red shoes blue socks))
Exercise. Two lists are said to be equal? if they contain equal elements arranged in the same order. For example,
(equal? '(this is a list) '(this is a list))is true, but
(equal? '(this is a list) '(this (is a) list))is false. To be more precise, we can define equal? recursively in terms of the basic eq? equality of symbols by saying that a and b are equal? if they are both symbols and the symbols are eq?, or if they are both lists such that (car a) is equal? to (car b) and (cdr a) is equal? to (cdr b). Using this idea, implement equal? as a procedure.
Exercise. Eva Lu Ator types to the interpreter the expression
(car ''abracadabra)To her surprise, the interpreter prints back quote. Explain.