Let's get Primitive!

Chapter: Let's get Primitive!

It doesn't seem very useful to have +, -, and * to be defined if we can't apply them. We will remedy this shortcoming of Mini-Scheme-B with our specification for Mini-Scheme-C:


<exp> ::= <number>			lit (datum)
        | <varref>			varref (var)
        | (<exp> {<exp>}*)		app (rator rands)

Finally, we have a language that can do something. It will not be very hard to derive Mini-Scheme-C from Mini-Scheme-B. We need to define a function that applies primitive operations. Luckily for us, +, * and - are already defined in Scheme. Here is the code we will need:

(define apply-prim-op
  (lambda (prim-op args)
    (case prim-op
      ((+) (+ (car args) (cadr args)))
      ((-) (- (car args) (cadr args)))
      ((*) (* (car args) (cadr args)))
      (else (error "Invalid prim-op name:" prim-op)))))

Note that in our implementation, (+ 2 3 4) equals 5, not 9. We may change this later.

Q. 7
Hey!! Wait a minute!!! What's all this? Using Scheme to Interpret Scheme and pretending that we've written our own interpreter!!! Isn't this a total fraud?


Here is the first installment of a general routine that applies functions which we will add to as we go along. Eventually, we will update this routine to include user-defined functions. For now, only primitive operations will be implemented.

(define apply-proc
  (lambda (proc args)
    (cond
      ((prim-proc? proc) (apply-prim-op (prim-proc-prim-op proc) args))
      (else (error 'apply-proc "Invalid procedure: " proc)))))

Our new interpreter and parser can be found in interp-c.ss and parse-c.ss.

> (load "parse-c.ss")
> (load "interp-c.ss")
> (read-eval-print)
MS> (* 2 3)
6
MS> (+ 2 4)
6
MS> (* 2 (+ 1 2))
6
MS> (* 2 (- 3 (+ 4 (* 7 (+ 2 3)))))
-72
MS> (+ 2 3 4 5 6)
5
MS> exit
returning-to-Scheme-proper
> 


Exercise 3

Write Mini-Scheme-D, an extension of Mini-Scheme-C, that supports three new primitive procedures: add1, sub1, and minus.

Mini-Scheme-D should behave as follows:

> (read-eval-print)
MS> minus
#[#{prim-proc btkejzjhs1b2wx3pgmot7k-1} minus]
MS> add1
#[#{prim-proc btkejzjhs1b2wx3pgmot7k-1} add1]
MS> sub1
#[#{prim-proc btkejzjhs1b2wx3pgmot7k-1} sub1]
MS> (minus (+ (add1 4) (sub1 (sub1 3))))
-6
MS> (add1 (* 3 4))
13
MS> exit
returning-to-Scheme-proper
> 

Save the files as "parse-d.ss" and "interp-d.ss".




Exercise 4

doesn't have list processing functions?!?!? Write Mini-Scheme-E, which implements attach, head, tail, list, and nth which should each behave like cons, car, cdr and list respectively, while nth behaves like list-ref except that it takes its arguments in reverse order. Whereas to find the 3rd member of (list 1 2 3 4 5) you would in Scheme type (list-ref (list 1 2 3 4 5) 2) in Mini-Scheme-E you will call (nth 2 (list 1 2 3 4 5)). The initial environment should also include a new variable, emptylist. Mini-Scheme-E should behave as follows:

> (load "interp-e.ss")
> (parse '(attach 1 emptylist))
#[#{app btkejzjhs1b2wx3pgmot7k-3} #[#{varref btkejzjhs1b2wx3pgmot7k-4} attach] (#[#{lit btkejzjhs1b2wx3pgmot7k-5} 1] #[#{varref btkejzjhs1b2wx3pgmot7k-4} emptylist])]
> (eval-exp (parse '(attach 1 emptylist)))
(1)
> (read-eval-print)
MS> emptylist
()
MS> (attach 2 emptylist)
(2)
MS> list
#[#{prim-proc btkejzjhs1b2wx3pgmot7k-7} list]
MS> (list 1 2 3 4 5)
(1 2 3 4 5)
MS> (nth 2 (list 1 2 3 4 5))
3
MS> (minus (head (attach 3 (attach 4 emptylist))))
-3
MS> 



rhyspj@gwu.edu