Sei sulla pagina 1di 7

2.

Getting Started in DrScheme 1

1 Getting Started

Get an account on guinness. Go to the system administrators’ office on the


first floor of Lieb. Bring a picture ID, and think of a password. Your password
should have some digits and/or punctuation symbols, as well as letters.
To run DrScheme, from anywhere type
ssh lab.cs
Once you have a shell, type
drscheme
Now, you’re in business.
If you want DrScheme on your own computer, Google “DrScheme” to find a
place from where you can download it.

2 Getting Started in DrScheme

There are several good texts on Scheme:

• SICP, The Structure and Interpretation of Computer Programs, by Abel-


son, Sussman and Sussman.
• Simply Scheme, by Harvey and Wight.
• The Little Schemer, by Friedman and Felleisen.

There is also an on-line manual:


http://download.plt-scheme.org/doc/drscheme/
which is quite good. To access it, click on the Help Desk from DrScheme, and
then on Languages.
The elementary part of Scheme that we will need can be learned quite quickly.
Scheme is a language quite close to mathematics. Each program (’procedure’)
can be viewed as a function.
We’ll cover some basic aspects of Scheme here.
Expressions are fully parenthesized, with the operator in the prefix position.

> (+ 2 3)
5
> (+ (* 4 5) 3)
23

1
2. Getting Started in DrScheme 2

We can name values: (define x 7). Then,

> x
7

Lists are a basic data type. There is the empty list, denoted null. To test
whether a list x is empty, use (null?x), which returns #t if x is null, and #f
otherwise.
If the list x = (a1 a2 . . .) is nonempty, then the element a1 is (car x) and the
list of all but the first element is (cdr x).
Functions are values, too.

(define square
(lambda (x) (* x x)))

Perhaps more conveniently, but with some loss of clarity, we can omit ’lambda’

(define (square x)
(* x x))

Some names are local (such as y below), while others are global (x below):

(define (add-x y)
(+ x y))

Function names can occur in the body of other functions.

(define (cube x)
(* x (square x)))

“square” is a global name.


We have conditionals:

(define (myabs x)
(cond ((> x 0) x)
((= x 0) 0)
(else (* -1 x))))

or

(define (myabs x)

2
2. Getting Started in DrScheme 3

(if (>= x 0) x
(* -1 x)
); end if
); end define

(Any text appearing to the right of a semicolon is ignored.)


The “if” construction,

(if (P) A
B)

is equivalent to

(cond
((P) A)
(else B)
)

Note: cond can be used when there are more than just two alternatives.
Let’s write a program to compute the maximum of two inputs

;pre: x and y are numbers


;post: returns the larger of the two inputs if they are distinct,
; and otherwise returns y

(define (mymax x y)
(cond ((> x y) x)
(else y)))

Exercise: What about the maximum of three inputs?


Let’s write a program to compute the sum of the squares of the two larger of
three inputs.

(define (sum-squares x y z)
(let ((m (min x y z)))
(cond ((= m x) (+ (square y) (square z)))
((= m y) (+ (square x) (square z)))
(else (+ (square x) (square y))))))

(define (square x)
(* x x))

3
2. Getting Started in DrScheme 4

Here, min is a pre-defined function, of arbitrary arity let is a special form – the
effect above is to define m locally.
What about repeating functions? First, recursion:

(define (fact x)
(cond ((= x 0) 1)
(else (* x (fact (- x 1))))))

To show that (fact n) correctly computes n! we need induction.


Basis step: start with the smallest legal input, that is, x = 0, and observe that (fact
0) = 1, which is correct.

Induction hypothesis: assume (fact k) works correctly, that is, that the value returned
by the call (fact k) is exactly the factorial of k (written k!)

Induction step: show, using the induction hypothesis, that (fact (+ k 1)) works cor-
rectly. According to the code, (fact (+ k 1)) returns (* (+ k 1) (fact k)). If (fact k)
= k!, as it must by the induction hypothesis, then multiplying it by (+ k 1) certainly
returns (+ k 1)!

The storage required by this program is proportional to x.


Compare the following

(define (new-fact x)
(fact-iter x 0 1))

;; where

(define (fact-iter x count result)


(if (= count x)
result
(fact-iter x (+ count 1) (* (+ count 1) result))))

We see here the use of an auxiliary function, fact-iter. We should make the
auxiliary function local:

(define (new-fact x)
(define (fact-iter count result)
(if (= count x)
result
(fact-iter (+ count 1) (* (+ count 1) result))))
(fact-iter 0 1))

To show the new program is correct, show that as the program runs, result =
count!

4
3. The meaning of Scheme programs 5

Why? If it holds when the program exits, and if count = x when the program
exits, then the value returned (namely, result) is equal to x! that is, we can use
the relation to show that the program works correctly.
Convince yourself that the new-fact / fact-iter pair require only constant space.
A recursive program which runs in constant space will be said to be tail recur-
sive. Other recursive functions will be said to be properly recursive.

3 The meaning of Scheme programs

The meaning of most programs is determined by the “substitution model”. For


example,

(define (a-plus-abs-b a b)
((if (>= b 0) + -) a b)

Then, the meaning of (a-plus-abs-b 3 -5) is obtained by substituting 3 for


a and -5 for b in the body of the definition:

((if (>= -5 0) + -) 3 -5)


;which is
> ((if #f + -) 3 -5)
; or
> (- 3 -5)
; or
8.

In most cases, Scheme uses the “applicative order evaluation”: to evaluate (e1
... em), first evaluate e1, ..., em and then apply the value of e1 to the values of
e2, ..., em.
The intention is that this evaluation rule is inductively defined. At the basis
step, we have those scheme expressions which evaluate to themselves – as, for
example, 7 evaluates to 7 and #t evaluates to #t.
We need to be somewhat careful in the application of this evaluation rule, and
in fact its completely uniform application breaks on ’special forms’, such as if,
cond, define ...
Note, for example, that

(let ((x 0))


(if (= x 0)
0
(p)))

5
4. From C++ to Scheme 6

evaluates to 0.

4 From C++ to Scheme

The language Scheme is a functional language. In particular, in Scheme you


don’t use constructs such as while (p) ... or for (i=0; i<10; ++i)....
To achieve the effect of a while loop, one typically uses an auxilliary function.
For example, here is a C++ function.

// precondtion: n>=0
int sum_of_squares(int n)
// post: returns 1*1 + 2*2 + ... + n*n
{
int sumsq = 0, i;
//invariant: sumsq = 1*1 + 2*2 + ... + (i-1)*(i-1)

for (i=1; i <= n; ++i)


sumsq = sumsq + (i*i);

return sumsq;
}

Here is an equivalent Scheme function.

(define (sum_of_squares n)
(define (aux i sumsq)
;; assume sumsq== sum of the first i-1 squares
(cond
((> i n) sumsq) ;; sumq is sum of first n squares
(else (aux (add1 i) (+ (* i i) sumsq)) )
); end cond
); end aux
(aux 1 0))

Note that the first line of cond is the termination condition. The way that
Scheme evaluates cond statements is top-down: the first condition that is true
determines the result. The last line applies aux to the intial values of the
program variables sumsq, i.
For a more complicated example, consider the following program to compute np
by “repeated squaring”.

//precondition: n>0, p>= 0

6
4. From C++ to Scheme 7

int pow(int n, int p)


//post: returns n^p
{
int x=n, k=p, z=1;
//invariant z * x^k == n^p
while (k>0)
{
if ( k%2 == 1 ) // p is odd
{ z=z*x; }
x=x*x; // if k even, z is unchanged
k=k/2; // integer division
}
// p == 0, so z == n^p
return z;
}

Here is the way to achieve the same thing in Scheme:

(define (pow n p)
(define (aux x k z)
(cond
((= 0 k) z)
((= 1 (remainder k 2) ) (aux (* x x) (quotient k 2) (* z x)))
(else (aux (* x x) (quotient k 2) z ))
); end cond
); end aux
(aux n p 1)
); end pow

You should study this example carefully. The while-loop of the C++ program
is replaced by a tail-recursive definition of the function aux.
Note that the first line of cond is the termination condition. The way that
Scheme evaluates cond statements is top-down: the first condition that is true
determines the result. The last line applies aux to the intial values of the
program variables x,k,z.

Potrebbero piacerti anche