Beginning Scheme

Algorithms and programs

Our objective in this course is to learn about algorithms -- step-by-step methods for solving problems -- and to learn how to direct computers to perform such algorithms for us. A programming language, such as Scheme, is a formal notation in which one can express algorithms so exactly that a computer can perform them without any other assistance from human beings. The expression of an algorithm in such a notation is called a program, and the computer is said to be executing the program when it is performing the algorithm as directed.

Although not all of the problems that we'd like computers to solve are arithmetical, the simplest examples belong to that category, and we'll start with a few of them. Here, for instance, is a program, written in Scheme, that directs the computer to find the answer to the question ``What is the square root of 137641?''

(sqrt 137641)

Let's begin today's lab by finding out how to get Scheme to execute this program and thereby answer the question.

Interacting with Scheme

Log in on any MathLAN workstation. If no dtterm window appears automatically, start one by clicking on the monitor-and-keyboard icon on the front panel. Type scheme at the shell prompt to start the Chez Scheme interactive interface, a program designed precisely to read in and execute programs written in Scheme.

When the Scheme prompt (a greater-than sign) appears, type in the program shown above. Press the <Enter> key after the right parenthesis. As soon as the interactive interface receives your program, it will execute it and print out the result of its computation. Because this particular program is extremely simple, the result will be printed immediately. At that point, the window should look like this:

bourbaki% scheme
Chez Scheme Version 5.0c
Copyright (c) 1994 Cadence Research Systems

> (sqrt 137641)
371
> 

It is not difficult to check, by pencil-and-paper computation or with the help of a pocket calculator, that 137641 is indeed the square of 371. (You don't have to take my word for it -- check it yourself.) So this first program is a success.

You probably noticed that Chez Scheme prints out another prompt after executing your program. This is because Chez Scheme cannot be sure that it has seen all the steps in the program. A program written in Scheme has a particularly simple structure: it is a sequence of definitions and commands -- any number of them, in any order. The Scheme interactive interface reacts to each definition by memorizing it and to each command by carrying out the command. (The expression (sqrt 137641) is a command -- ``Compute the square root of 137641!'') Because a program might contain several commands rather than just one, the interactive interpreter has to be prepared to receive another after carrying out the first.

The <Ctrl/D> that you type to exit from the interactive interface is really a signal indicating the end of a program that consists of all the definitions and commands that you have issued during your session with Chez Scheme. Chez Scheme will always expect another input and generate another prompt until it receives some such signal and exits.

Procedure calls

The Chez Scheme interactive interface contains several hundred built-in procedures -- operations, such as finding the square root of a number, for which the interface can use prepackaged algorithms. Some programmers who are experts on square roots and on the idiosyncracies of the HP workstations' central processing unit (the electronic circuit that directs the movement and transformation of data inside the computer) have figured out and written up a step-by-step method for computing the square root of any number, using only the very elementary transformations that the central processing unit can perform. Chez Scheme recognizes sqrt as the name of this algorithm and knows where the processor instructions that carry it out are stored. When Chez Scheme receives a command to compute a square root, it recovers these instructions and executes them.

A procedure call is a command that directs the interactive interface to activate a built-in procedure such as sqrt. (So sqrt is the procedure and (sqrt 137641) is the procedure call.) In Scheme, every procedure call begins with a left parenthesis and ends with the matching right parenthesis. Within the parentheses, one always begins by identifying the procedure to be called and then continues by identifying the operands -- the values that the procedure is supposed to operate on. A call to the sqrt procedure has only one operand -- the number of which you want the square root -- but other procedures can have two or more operands, and some have no operands at all.

All arithmetic in Scheme is done with procedure calls. The built-in procedure + adds numbers together, the built-in procedure - subtracts one number from another. Similarly, the built-in procedure * performs multiplication, and the built-in procedure / performs division. The fact that in a procedure call the procedure is identified first makes calls to these procedures look different from ordinary arithmetic expressions: For instance, to tell Chez Scheme to subtract 68343 from 81722, one gives the command (- 81722 68343), thus:

> (- 81722 68343)
13379

Exercise 1

Tell Chez Scheme to multiply 162 by 1383.


Exercise 2

The Scheme procedure abs computes the absolute value of its operand. Tell Scheme to compute the absolute value of -197.


Exercise 3

The Scheme procedure for raising a number to some power is called expt. Tell Scheme to find the cube of 189 (that is, to raise 189 to the power 3).


Exercise 4

It is harmless, though unproductive, to try to give Chez Scheme ordinary arithmetic expressions, in which the procedure is written between the operands. Try it: Type each of the following expressions at the Scheme prompt and see what reaction you get.

  1. (2 + 3)
  2. 7 * 9
  3. sqrt(49)

Here are the explanations:

  1. When Chez Scheme sees the left parenthesis at the beginning of the expression (2 + 3), it expects the expression to be a procedure call, and it expects the procedure to be identified right after the left parentheses. But 2 does not identify a procedure; it stands for a number. So Chez Scheme complains that it cannot ``apply'' or execute something that is not a procedure.

  2. In the absence of parentheses, Chez Scheme sees 7 * 9 as three separate and unrelated expressions -- the numeral 7; *, a name for the built-in multiplication procedure; and 9, another numeral. It interprets each of these as a command to evaluate an expression: ``Compute the value of the numeral 7! Find out what the name * stands for! Compute the value of the numeral 9!'' So it performs the first of these commands, displays 7, and issues a prompt; then it carries out the second command, reports that * is the name of the system procedure *, and issues another prompt; and finally it carries out the third command, displays the result, 9, and issues yet another prompt. This behavior is confusing, but it's strictly logical if you look at it from the computer's point of view (remembering that the computer has absolutely no common sense).

  3. As in the preceding case, Chez Scheme sees this as two separate commands: sqrt means ``Find out what sqrt is!'' and (49) means ``Call the procedure 49, with no operands!'' Chez Scheme responds to the first command by reporting that sqrt is the system procedure for computing square roots and to the second by pointing out that the number 49 is not a procedure.


Definitions

The interactive interface can also learn new names for things by reading definitions. Here's what a definition looks like:

(define days-in-a-week 7)

Like a procedure call, a definition begins and ends with matching parentheses. To distinguish between definitions and procedure calls, Chez Scheme looks at what comes right after the left parenthesis; in a definition, the keyword define must appear at that point. Define is not the name of a procedure; it is part of the syntactic structure of the Scheme programming language -- its only role is to serve as the mark of a definition.

After the keyword define, a definition contains the name being defined and an expression that identifies the value that the name should stand for. In this example, the name is days-in-a-week -- notice that in Scheme the symbol that names something can (and often does) contain hyphens internally -- and the value that it names is the number 7. Once Chez Scheme has seen this definition, it remembers that days-in-a-week stands for 7:

> (define days-in-a-week 7)
> (* days-in-a-week 5)
35

The value that gets a new name need not be a number; it can be anything, even a procedure. For example, if you don't like the name * for the multiplication procedure and would rather call it by the name multiply, just start each session with Chez Scheme by typing in (define multiply *).


Exercise 5

Write a definition that will cause Scheme to recognize dozen as a name for the number 12.


Exercise 6

Write a definition that will cause Scheme to recognize raise-to-power as a synonym for expt.


More procedures

At this point, I hope you're wondering what other useful and interesting procedures are built into Scheme. Section 6.5.5 of the Revised4 report on the algorithmic language Scheme contains a list of the ones that are mainly about numbers, and that's only one section of the full roster of standard Scheme procedures. Fortunately, most of the built-in procedures perform small, simple jobs and are very easily learned.


This document is available on the World Wide Web as

http://www.math.grin.edu/~stone/courses/scheme/beginning-Scheme.html

created August 23, 1997
last revised January 15, 1998

John David Stone (stone@math.grin.edu)