CS 51 Week 1, L1: The Best Laid Scheme


Today's topics: Announcements:


Week 1 Pithy Design Quotes

The K.I.S.S. Principle = Keep it simple, stupid! (anonymous)
Fools ignore complexity. Pragmatists suffer it. Geniuses remove it.
(Alan Perlis, Epigrams in Programming)

Abstraction And Design

Why we are here:

Introduction to Scheme

The Goal of Week 1 is to learn everything you need to know about writing simple programs in the Scheme programming language.

What exactly is Scheme?

Scheme is

BUT THE MOST IMPORTANT THING YOU NEED TO KNOW ABOUT SCHEME IS:....



History of Scheme

"We were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp."
--- Guy Steele, co-author of the Java spec (May 2002)

Parts of the Language

Every powerful language has

(Just think Legos!)

In Scheme we have:

Primitives

Means of combination

We can combine the primitives to create expressions (function arg1 arg2 arg3...)

And this is really our only means of combination. Everything in Scheme looks like this applying a FUNCTION to a set of ARGUMENTS.

For example

              (- (+ 3 3 50) 5)
	      (equal? 5 'hello)

Means of abstraction

How do we create new primitives (data and procedures)?

We can name variables

      	 (define a 51)
      	 (define b (+ 25 26))
      	 (define c (equal? a 3)) <--- we can pretend a is just another simple entity

We can create named procedures

      	 (define (square x) (* x x))
	 (define (hello? x) (equal? x 'hello))
	 (square 51)            <--- we can pretend square is another primitive procedure

The interpreter's point of view

What is an interpreter and what does it do?

Interpreter vs Compiler

So you can think of the interpreter as reading expressions in your program and evaluating it piece by piece. Here's a simple (but somewhat meaningless) scheme program.

  51
  #t
  (- 54 3)
  (+ (- 54 3) 101)
  foo
  (define  foo 3)
  (+ foo 48)

How does the interpreter evaluate this?


THE EVALUATOR MANTRAS: (version 1)

  1. (Almost) every expression has a value

  2. If not a combination, then find the value as follows
    • if self-evaluating, return value
    • if procedure, then return a "procedure object".
    • if name, then return value associated with name

  3. To find the value of a combination
    • Evaluate all the subexpressions (in any order)
    • Apply the leftmost value (operator)
      to the rest of the values (arguments)
      and return the result

Lets do some examples (from the interpreter's point of view)

>  51

>  (- 54 3)

>  (+ (- 54 3) 101)

>  (+ foo 48)

>  (define  foo 3)

>  (+ foo 48)


Questions:


Special Forms


THE MANTRAS: (version 2)

  1. 1. (Almost) every expression has a value

  2. If not a combination, then find the value as follows
    • if self-evaluating, return value
    • if procedure, then return a "procedure object".
    • if name, then return value associated with name

  3. If a special form, do something special...

  4. Otherwise, to find the value of a combination
    • Evaluate all the subexpressions (in any order)
    • Apply the leftmost value (operator)
      to the rest of the values (arguments)
      and return the result

Special Form: IF

  (if predicate then-expression else-expression)

Evaluation Rules

Examples

>  (define a 3)
>  (if (= a 5) 'five 'notfive)


Challenge Problem:

I'd like to create a new version of if, that always has false for the else-expression. What is wrong with this? (Illustrate with an EXAMPLE)

  	(define (newif predicate then-expression) 
	     (if predicate then-expression #f))







Special Form: DEFINE

  (define name expression)

Evaluation rules

Some Examples:

> (define a (+ 2 3))              <------ returns no value! binds a-->5

> a
5

> (+ (define a 3) 3)              <------ interpreter returns an error
error:: define: not allowed in an expression context

> (define (square x) (* x x))     <------ binds square--> [PROC (n) (* n n)]

> square
#

> (square 3)
9

What happens when we apply a procedure created using define?

The Substitution Model

To APPLY a compound procedure to arguments, evaluate the BODY of the procedure with each formal parameter replaced by the corresponding argument.

Example:








Other Special Forms

There are a number of special forms, some of which you will see in section and others that you will only see in later lectures.

Special Forms:





Quick Recap

The basic syntax of Scheme is an expression

     (function subexpression subexpression ...)

Internalize the 4 Mantras!
    -- they will help you predict how your code will behave

There is really not much more!

  (+ 2 3)
  (define a 3)
  (+ 2 (if (> a 10) 5 6))  <-- lots of parens but VERY SIMPLE STRUCTURE

Recursion

How do we create loops in this language? We can create loops by having a function call itself, i.e. by writing a recusrive procedure.

Example 1: Factorial

  n! = n * (n-1) * (n-2) ....* 1


  fact(n) =  | n * (n-1)!       if n > 0
             | 1                if n <= 0

In Scheme

  (define (fact n) 
	(if (<= n 0)
	    1
	    (* n (fact (- n 1))) 
	    ))

Lets look at this from the interpreter's point of view

> (define (fact n) .....)
...
> (fact 3)






Example 2: Counting

Print a row of numbers seperated by " : ", representing the axis of a graph or the heading for a table.

> (print-row 4 10)
4  :  5  :  6  :  7  :  8  :  9  :  done

In Scheme,

(define (print-row start end)
    (if (>= start end)
	'done
	(begin (display start) (display "  :  ")
	       (print-row (+ start 1) end))
	))

From the interpreter's point of view

> (print-row 4 10)



The Basic Structure of Recursion

  • RECURSIVE STEP: how does the problem translate to solving a smaller version of the same problem
  • BASE CASE: how and when do you stop?

Recursion is a very natural and powerful idea, that comes up alot.


The Escher Recurse Painter
----------------------------
(define (escher-recurse-image ntimes img)
  (if (<= ntimes 0)
      (make-four-image img img img img)    ; return an image tiled with 4 of given image
      ; otherwise let the topleft be the given image, but "escherize" the rest
      (make-four-image img
                       (escher-recurse-image (- ntimes 1) (half-image img))
                       (escher-recurse-image (- ntimes 1) (half-image img))
                       (escher-recurse-image (- ntimes 1) (half-image img)))
      ))




CS51, Spring 2008, Radhika Nagpal