Some Additional Scheme Topics: Quoting, Eval, Apply, and Functions with Variable Numbers of Arguments

Symbols and Quoting

In addition to data types such as integers, booleans, and lists, an important data type in Scheme is a symbol, for example x or squid. To type in a symbol to the interpreter or in a function definition, you need to quote it:


'x

'squid

(Otherwise you'd be finding what x or squid is bound to.)

You can also quote lists to prevent evaluation. Compare:


(abs 10)

'(abs 10)

The first expression evaluates to 10, the second to the list (abs 10) Or try:

(john paul george ringo)

'(john paul george ringo)

More on Symbols

Scheme has a much more liberal idea of what you can include in a symbol than most languages. For example the following are all symbols:


symbol?

*x*

squid++

x



This is sometimes the source of puzzling errors.  Compare:


(* 3 5)

(*3 5)

eval

The eval function takes a Scheme object and evaluates it. Examples:

(define fn '*)

(define x 3)

(define y (list '+ x 5))

(define z (list fn 10 y))

x  =>  3

y  => (+ 3 5)

z  => (* 10 (+ 3 5))

(eval '(+ 6 6))  => 12

(eval y)  => 8

(eval z)  => 80

An example of variables whose values are symbols:

(define a 'b)

(define b 'c)

(define c 50)

a => b

(eval a)  => c

(eval (eval a))  => 50

Numbers just evaluate to themselves, so:

(eval (eval (eval a)))  => 50

(eval (eval (eval (eval a))))  => 50

Other things that evaluate to themselves are #t, #f, and ().

The top level of the Scheme interpreter is a read-eval-print loop: read in an expression, evaluate it, and print the result.

Quote suppresses evaluation; eval causes evaluation. They can cancel each other out.


(define x 3)

x  =>  3

'x => x

(eval 'x)  => 3

apply

The apply function applies a function to a list of its arguments. Examples:

(apply factorial '(3))  => 6

(apply + '(1 2 3 4))  => 10

A useful programming trick is to use apply to define a function that takes a list of arguments, if you have available a function that arbitrary number of arguments. Example:

(define (sum s) (apply + s))

(sum '(1 2 3))  => 6

Functions with a Variable Number of Arguments

We've used functions with a variable number of arguments (for example +), but have only written them with a fixed number of arguments.

Example definitions with a variable number of arguments:


(define (squid a b . c)

   (display a) (newline)

   (display b) (newline)

   (display c) (newline))

squid requires at least 2 arguments. Any remaining arguments (perhaps 0) are put into a list, which is bound to c.

This function can take 0 or more arguments:


(define (average . lst)

   (if (null? lst) 

      0 

      (/ (sum lst) (length lst))))

Quasiquotes

"Backquote" or "quasiquote" expressions are useful when you want to construct a list for which you know most, but not all, of the desired structure in advance. For example, suppose that you want to return a list of band members that includes a mysterious 5th Beatle. With what we know so far you could do this:


(define (bands m)

   (list '(peter paul mary)

         (list 'john 'paul 'george 'ringo m)

         '(simon garfunkle)))

Since we know all of the structure except for the 5th Beatle, instead we could use quasiquoting:

(define (quasibands m)

   `((peter paul mary)

     (john paul george ringo ,m)

     (simon garfunkle)))

Here everything in the quasiquoted list is quoted, except when it is preceded by a comma (which unquotes it).

You can also splice in a list in the middle of another using an @ sign.


(define x '(clam squid))

Then

`(octopus ,@x mollusc oyster) => (octopus clam squid mollusc oyster)

compare with:

`(octopus ,x mollusc oyster) => (octopus (clam squid) mollusc oyster)

Advanced Topic - Nested Quotes


(define x 3)

'''x  => ''x

(eval '''x)  => 'x

(eval (eval '''x))  => x

(eval (eval (eval '''x)))  => 3

Nested Quasiquoting

From the R5RS Scheme Report:
Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing at the same nesting level as the outermost backquote. The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.
This is probably not something you would actually do in a program, but language designers need to account for it -- and it's better to have a uniform treatment of the construct (as Scheme does) than something ad hoc.