This lecture will deal with the second extra credit problem on the Scheme project.
A Scheme expression is a Scheme list. Scheme programs consist of expressions such as:
The built-in Scheme list data structure (a linked list) can represent combinations
scm> (list `quotient 10 2) (quotient 10 2) scm> (eval (list `quotient 10 2)) 5
In such a language, it is straightforward to write a program that writes a program.
Let's look at a couple of examples of a program writing a program.
(define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) (define (fact-exp n) (if (= n 0) 1 (list '* n (fact-exp (- n 1)))))
(fact 5) yields
(fact-exp 5) yields the expression for computing
(* 5 (* 4 (* 3 (* 2 (* 1 1)))))
(define (fib n) (if (<= n 1) n (+ (fib (- n 2)) (fib (- n 1))))) (define (fib-exp n) (if (<= n 1) n (list '+ (fib-exp (- n 2)) (fib-exp (- n 1)))))
Same idea here.
(fib-exp n) will yield the expression for computing
(fib n) without actually computing
A macro is an operation performed on the source code of a program before evaluation. They exist in many languages, but are easiest to correctly define in languages like Lisp where every expression is a list.
Scheme has a
define-macro special form that defines a source code transformation.
(define-macro (twice expr) (list 'begin expr expr)) scm> (twice (print 2)) ; this is equivalent to the following scm> (begin (print 2) (print 2)); both of these print: 2 2
Evaluation procedure of a macro call expression:
Define a macro that evaluates an expression for each value in a sequence.
scm> (map (lambda (x) (* x x)) '(2 3 4 5)) (define-macro (for sym vals expr) (list 'map (list 'lambda (list sym) expr) vals) ) scm> (for x '(2 3 4 5) (* x x)) (4 9 16 25)
This example just created a
for form in Scheme. The power of defining macros is that it allows you to extend the programming language in new ways!
scm> '(a b c) (a b c) scm> `(a b c) (a b c) scm> (define b 3) b scm> `(a b c) (a b c) scm> `(a ,b c) (a 3 c)
Quasi-quotes are the ` character, as opposed to quotes which are the ' character.
scm> (quasiquote (a (unquote b) c)) (a 3 c) scm> `(a (,b) c) (a (3) c) scm> `(a ,(+ 2 b) c) (a 5 c)
This allows for some simplification. Consider the following code:
(define-macro (check expr) (list 'if expr ''pass (list 'quote (list 'fail: expr))))
This code does the same thing as:
(define-macro (check expr) `(if ,expr 'pass '(fail: ,expr)))