# Scheme Programs as Data

Tips for navigating the slides:
• Press O or Escape for overview mode.
• Visit this link for a nice printable version
• Press the copy icon on the upper right of code blocks to copy the code

### Class outline:

• Eval
• Quasiquotation
• Generating code
• Apply

### A Scheme Expression is a Scheme List

Scheme programs consist of expressions, which can be:

• Primitive expressions: 2 3.3 #t + quotient
• Combinations: (quotient 10 2) (not #t)

The built-in Scheme list data structure can represent combinations:


(list 'quotient 10 2)        ; (quotient 10 2)


### The eval procedure

The eval procedure evaluates a given expression in the current environment.


(eval <expression>)


(eval (list 'quotient 10 2))  ; 5


Quote supresses evaluation, while eval forces evaluation. They can cancel each other out!


(define x 3)
'x           ; x
(eval 'x)    ; 3


## Generating call expressions

### Generating factorial expressions

Compare standard factorial:


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


(fact 5)  ; 120


...to a version that generates an expression:


(define (fact-exp n)
(if (= n 0)
1
(list '* n (fact-exp (- n 1)))))


(fact-exp 5)        ; (* 5 (* 4 (* 3 (* 2 (* 1 1)))))
(eval (fact-exp 5)) ; 5


### Generating virfib expressions

Compare standard Virahanka-Fibonacci:


(define (virfib n)
(if (<= n 1)
n
(+ (virfib (- n 2)) (virfib (- n 1)))))


(virfib 6)  ; 8


...to a version that generates an expression:


(define (virfib-exp n)
(if (<= n 1)
n
(list '+ (virfib-exp (- n 2)) (virfib-exp (- n 1)))))


(virfib-exp 6)        ; (+ (+ (+ 0 1) (+ 1 (+ 0 1))) (+ (+ 1 (+ 0 1)) (+ (+ 0 1) (+ 1 (+ 0 1)))))
(eval (virfib-exp 6)) ; 8


## Generating programs

### Quasiquotation

There are two ways to quote an expression:

 Quote '(a b) → (a b) Quasiquote (a b) → (a b)

They are different because parts of a quasiquoted expression can be unquoted with ,

 (define b 4) Quote '(a ,(+ b 1)) → (a (unquote (+ b 1)) Quasiquote (a ,(+ b 1)) → (a 5)

### Generating code with quasiquotation

Quasiquotation is particularly convenient for generating Scheme expressions:


(define (make-adder n) (lambda (d) (+ d ,n)))

(make-adder 2)        ; (lambda (d) (+ d 2))


Remember, the generated expression is a Scheme list:



new-func         ; (lambda (d) (+ d 2))
(list? new-func) ; #t
(car new-func)   ; lambda


### Example: While loops

Calculate the sum of the squares of even numbers less than 10, starting with 2

  x = 2 total = 0 while x < 10: total = total + x * x x = x + 2   (begin (define (loop x total) (if (< x 10) (loop (+ x 2) (+ total (* x x))) total)) (loop 2 0)) 

Calculate the sum of numbers whose squares are less than 50, starting with 1

  x = 1 total = 0 while x * x < 50: total = total + x x = x + 1   (begin (define (loop x total) (if (< (* x x) 50) (loop (+ x 1) (+ total x)) total)) (loop 1 0)) 

### Generating while loops

Could a procedure generate custom loop expressions for us?


(define (sum-while initial-x condition add-to-total update-x)

)


The goal is for this call:


(sum-while 1 '(< (* x x) 50) 'x '(+ x 1))


...to generate this expression:


(begin (define (loop x total)
(if (< (* x x) 50)
(loop (+ x 1) (+ total x))
total))
(loop 1 0))


### Generating while loops (Solution)


(define (sum-while initial-x condition add-to-total update-x)
(begin (define (loop x total)
(if ,condition
(loop ,update-x (+ total ,add-to-total ))
total))
(loop ,initial-x 0))
)


(sum-while 1 '(< (* x x) 50) 'x '(+ x 1))
; (begin (define (loop x total) (if (< (* x x) 50) (loop (+ x 1) (+ total x)) total)) (loop 1 0))


(eval (sum-while 1 '(< (* x x) 50) 'x '(+ x 1))) ; 28


(eval (sum-while 2 '(< x 10) '(* x x) '(+ x 2))) ; 120


## Apply

### The apply procedure

The apply procedure applies a given procedure to a list of arguments.


(apply <procedure> <arguments>)


Examples:


(apply + '(1 2 3 ))


(define (sum s) (apply + s))

(sum '(1 2 3))


### Combining eval and apply

A function that can apply any function expression to any list of arguments:


(define (call-func func-expression func-args)
(apply (eval func-expression) func-args)
)


(call-func '(lambda (a b) (+ a b)) '(3 4))  ; 7