Quasiquotation
- We may extend Lisp as a language itself.
- We may change the language however we want.
- We may extend Scheme by adding more procedures to it, such as a for loop function.
- Quasiquotation is like quotation, but we can fill stuff into along the way with other values.
- Quote: ‘(a b) = > (a b)
- Quasiquote: `(a, b) => (a b)
- Parts of a quasi-quoted expression can be escaped (unquoted) and be evaluated with a
,
to evaluate sub-expressions- Ex:
1
2
3
4
5
6
7
8
scm> (define b 4)
b
scm> '(a (+ b 1))
(a (+ b 1))
scm> `(a (+ b 1))
(a (+ b 1))
scm> `(a ,(+ b 1))
(a 5)
- We may also create lambda expressions creatively through this method:
1
2
3
4
scm> (define n 2)
n
scm> `(lambda (d) (+d ,n))
(lamdda (d) (+ d 2))
- Note that
,
only unquotes what immediately follows itself.- We must wrap everything in a () if we want to unquote multiple
- Question: Use quasiquotation to define fact=expr, a procedure that takes an integer n and returns a nested multiplication expression that evaluates to n factorial
1
2
(define (fact-expr n)
(if (<= n 1) 1 `(* ,n ,(fact-expr (- n 1)))))
Macros
- To change how scheme behaves, we must add special forms
- In scheme, we only have primitives, call expressions, and speicla forms.
- Macros change the code before it gets run. It is an operation that is performed on the source code of a program before evaluation.
- Scheme has a define-macro special form that defines a source code transformation
- The arguments in the signature of a macro are not automatically evaluated when we call the macro, so we must manually evaluate it.
- Ex: Execute an expression twice.
1
2
3
4
scm> (define-macro (twice expr) (list `begin expr expr))
scm> (twice (print 2))
2
2
- Evaluation procedure of a macro call expression:
- Evaluate the operator sub-expression, which evaluates to a macro
- Call the macro procedure on the operand expressions wihout evaluating them first
- Evaluate the expression returned from the macro expression.
- We use this because a normal scheme define would eval whatever expression we pass into the function.
- Ex:
1
2
3
4
5
scm> (define (twice expr) (list 'begin expr expr))
twice
scm> (twice (print 2)) ; (print 2) would be EVALUATED before it is passed into the twice function
2
(begin undefined undefined) ; print returns undefined
- Discussion Question: Repeat
- Define repeat, a macro that is called on a number n and an expresion expr. It evaluates expr n times, and its value is the final result
1
2
3
4
5
6
7
(define (repeated-expr n expr)
(if (zero? n) nil (cons expr (repeated-expr (- n 1) expr)))
)
(define-macro (repeat n expr)
(cons 'begin (repeated-expr (eval n) expr))
)
For Macro
- Define a
for
macro that evaluates an expression for each value in a sequence
1
2
3
4
5
6
7
8
scm> (for x '(2 3 4 5) (* x x))
(4 9 16 25)
scm> (define-macro (for sym vals expr)
(list 'map (list 'lambda (list sym) expr) vals)
)
scm> (define-macro (for sym vals
`(map (lambda (,sym) ,expr) ,vals)
))