Home CS61A: Lecture 30
Post
Cancel

CS61A: Lecture 30

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)
))
This post is licensed under CC BY 4.0 by the author.

CS61A: Programs as Data

CS61A: Macros