123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- ;;; ================
- ;;; WHY syntax-case?
- ;;; ================
- ;; 1. syntax-case is able to match a form only if it is an identifier
- ;; 2. to be able to use "guard clauses"
- ;; You can ask if something (a syntax-object) the macro was given is an identifier with:
- ;; (identifier? some-syntax-object)
- ;; Even in guard clauses one needs to use:
- ;; (identifier? (syntax something))
- ;; instead of:
- ;; (identifier? something)
- ;; because identifier? needs the context information of a syntax object.
- ;; Here is an example for using the identifier? predicate:
- ;; The first macro is very simple and simply adds 1 to any expression it gets.
- (define-syntax add1
- (lambda (x)
- (syntax-case x ()
- ((_ exp)
- (syntax (+ exp 1))))))
- ;; The second macro in effect filters the add1 macro, by only allowing
- ;; identifiers through usage of a guard clause.
- (define-syntax add1!
- (lambda (x)
- (syntax-case x ()
- [(add1! var) ; pattern matching
- (identifier? (syntax var)) ; guard clause
- (syntax (set! var (add1 var)))])))
- (define foo 0)
- (add1! foo) ; foo -> 1
- (add1! "not-an-identifier") ; -> error
- ;; The following does not work:
- ;; "The reason that this doesn’t work is that, by default, the expander will
- ;; preserve referential transparency; the then and else expressions won’t have
- ;; access to the binding of it."
- (define-syntax aif
- (lambda (x)
- (syntax-case x ()
- [(aif test then else)
- (syntax (let ((it test)))
- (if it then else))])))
- ;; =========
- ;; EXAMPLE 1
- ;; =========
- ;; using syntax-case - a first example
- (define-syntax when
- (syntax-rules ()
- ((_ test e e* ...)
- (if test (begin e e* ...)))))
- (define-syntax when
- (lambda (x) ; wrap it in a lambda when using
- ; syntax-case
- ; "[...] the lambda wrapper is simply a
- ; leaky implementation detail."
- (syntax-case x () ; The first argument is not the
- ; ellipsis identifier anymore.
- ; In parens are probably still the literals.
- ; "[...] syntax transformers are just
- ; functions that transform syntax to syntax.
- ((_ test e e* ...) ; One can apparently still use _ instead of
- ; a name.
- #'(if test (begin e e* ...)) ; #' is equivalent to (syntax <?>)
- ))))
- ;; is equivalent to:
- (define-syntax when
- (lambda (x)
- (syntax-case x ()
- ((_ test e e* ...)
- (syntax (if test
- (begin e e* ...)))))))
- ;; =========
- ;; EXAMPLE 2
- ;; =========
- ;; How are syntax-case macros more powerful than syntax-rules macros?
- (define-syntax add1
- (lambda (x)
- (syntax-case x ()
- ((_ exp)
- (syntax (+ exp 1))))))
- ;; relying on previous add1 definition
- (define-syntax add1!
- (lambda (x)
- (syntax-case x ()
- [(_ var) (identifier? (syntax var))
- ;; (1) apparently one can define conditions here --> guard clause!
- ;; (2) `identifier?` asks if a syntax object is an identifer.
- ;; To the expander `var` is more than only a symbol.
- ;; This way `identifer?` can know about this.
- (syntax (set! var (add1 var)))])))
- (define foo 0)
- (add1! foo) ; foo ⇒ 1
- (add1! "not-an-identifier") ; ⇒ error
- ;; =========
- ;; EXAMPLE 3
- ;; =========
- ;; For example, in
- ;; (aif (foo) (bar it))
- ;; `it`
- ;; would be bound to the result of
- ;; (foo).
- ;; (aif (foo) (bar it))
- ;; --v-- ^
- ;; | |
- ;; `-->-->--´
- ;; result goes here
- ;;
- ;; The following doesn't work:
- (define-syntax aif
- (lambda (x)
- (syntax-case x ()
- [(_ test then else)
- (syntax
- (let ((it test))
- (if it then else)))])))
|