Scheme Programming/A taste of Scheme
Now that we have an idea of how to run a Scheme interpreter, let's see what we can do with it in some short examples. We won't consider these programs in any depth. For now, the intention is to give the reader a feel for Scheme.
A Scheme interpreter evaluates Scheme expressions typed by the user. With our interpreter running, we first evaluate a very simple expression.
> 4
4
When we enter '4' and hit Enter, we are asking our Scheme interpreter to evaluate the expression '4'. Unsurprisingly, 4 evaluates to 4.
Next, we try some basic arithmetic.
> (+ 3 6)
9
> (* 18 5) ; multiplication
90
> ( 4 7)
3
These examples illustrate some important things about Scheme syntax. First, the syntax is fullyparenthesized; the parentheses in the above expressions are required, and extra parentheses cannot be added without changing the meaning of the expression. For example, the following causes the interpreter to report an error:
> ((+ 3 6))
;; Error: application of nonprocedure 9
Secondly, we see that Scheme uses prefix notation. In each expression, the operator (+, *, ) comes before the operands (the numbers). This is unlike the usual ("infix") convention of mathematical notation, in which the operator is written between the operands. For example, the following isn't a valid Scheme expression:
> (8 * 5  3)
;; Error: application of nonprocedure 5
It's easy to translate it into Scheme, however:
> ( (* 8 5) 3)
37
Notice that here we've used the expression (* 8 5)
as an
operand of another expression! This is valid Scheme, and we will see
such nested expressions everywhere.
Scheme allows us to name values for use in other expressions:
> (define x 20)
> x
20
> (define y (+ x 4))
> (* y 2)
48
The definition (define x 20)
causes the interpreter to
define x
to mean the value 20
. When x
appears in code following the definition, it will be replaced by this
value. We can then use x
in the definition of y
.
We can also define procedures. Like the builtin operators
+
, 
, etc., a procedure takes a certain number
of parameters (also known as arguments) and computes a value.
> (define (square x)
(* x x))
> (square 5)
25
Here, we have defined square
to mean a procedure taking one
parameter, x
, and returning the value of (* x x)
.
The form of this definition is a little different from those we saw
earlier; here, the name being defined appears in parentheses, followed
by the names of the procedure's parameters. To use this newlydefined
procedure, we evaluate (square 5)
.
Here's a more complex procedure which calculates the area of a triangle with sides , , and using Heron's formula:
> (define (heron a b c)
(let ((s (/ (+ a b c) 2)))
(sqrt (* s ( s a) ( s b) ( s c)))))
> (heron 4 13 15)
24
In this procedure, we need to use the value , defined by
 ,
four times. The definition of heron
would be tedious to
write and hard to read if we were to use (/ (+ a b c) 2)
^{[1]}
for each occurrence of . We solve this problem using the
let
form, which allows us to temporarily associate the name
s
with this value.^{[2]}
We can compare values, or test them for certain properties.
> (= 4 (+ 3 1))
#t
> (< 9 7)
#f
> (positive? 5)
#t
> (even? 5)
#f
What are the #t
and #f
values which Scheme
gives us back here? As you may have guessed, these are boolean
values representing "true" and "false", respectively.
Predicates like positive?
are procedures which take
one argument and return a boolean value. It's a Scheme convention to
give predicates names ending with '?'; hence we have even?
,
negative?
, and many others.
Procedures can be recursive. Here's a classic example.
> (define (factorial n)
(if (= n 0)
1
(* n (factorial ( n 1)))))
> (factorial 5)
120
Evaluating (factorial 5)
gives us the value of ,
that is, , which we can
express recursively as . More generally, we
say that factorial of is 1 if is zero, and
times the factorial of otherwise. This
is precisely what the definition of factorial
states in the
language of Scheme:
(define (factorial n)
(if (= n 0) ; is the argument 0?
1 ; then the answer is 1
(* n (factorial ( n 1))))) ; otherwise, it's n * (n  1)!
Recursion is a critical notion in Scheme (and in computer science in general) that we will discuss in greater depth in later sections.
Another new thing in the definition of factorial
is the use of
the if
form, which evaluates its first argument, then either its
second or third argument depending on whether the first was true or false.
If the first argument evaluates to true, then we get the second argument of
the if
form; otherwise, we get the third.
^{[3]}
> (if #t 1 0)
1
> (if (> 2 3) 1 0)
0
Exercises (Solutions) 


 ↑ In previous examples we gave
+
two arguments. Here, though, we've given it three. Is this correct? In general, Scheme will report an error if we give a procedure too few or too many arguments.+
, though, is a variadic procedure, which means that it can be passed any number of arguments. The expression(+ a b c)
is equivalent to(+ (+ a b) c)
.
,*
, and/
are also variadic.  ↑ If you're familiar with programming
languages with "local variables", you can think of names bound by
let
as much the same thing.  ↑ For now, we'll assume that saying something is "true or false" means it's
a booleanthat is, either
#t
or#f
. In practice, every Scheme object has a boolean value; namely,#f
is false and everything else is true.