add a little more about quasiquote to the guide

Please merge to the 5.1 release branch
This commit is contained in:
Robby Findler 2011-02-04 13:06:23 -06:00
parent 8f404a4618
commit 74f8b0e2f1
2 changed files with 113 additions and 0 deletions

View File

@ -119,6 +119,22 @@ pattern variables can be bound to lists of lists of matches:
[(list (list '! x ...) ...) x])
]
The @racket[quasiquote] form (see @secref["qq"] for more about it) can also be used to build patterns.
While unquoted portions of a normal quasiquoted form mean regular racket evaluation, here unquoted
portions mean go back to regular pattern matching.
So, in the example below, the with expression is the pattern and it gets rewritten into the
application expression, using quasiquote as a pattern in the first instance and quasiquote
to build an expression in the second.
@interaction[
#:eval match-eval
(match `{with {x 1} {+ x 1}}
[`{with {,id ,rhs} ,body}
`{{lambda {,id} ,body} ,rhs}])
]
For information on many more pattern forms, see @racketmodname[racket/match].
Forms like @racket[match-let] and @racket[match-lambda] support

View File

@ -24,6 +24,63 @@ evaluated to produce a value that takes the place of the
`(1 2 ,(+ 1 2), (- 5 1)))
]
This form can be used to write functions that build lists according to
certain patterns.
@examples[
(eval:alts (define (deep n)
(cond
[(zero? n) 0]
[else
(#,qq ((#,uq n) (#,uq (deep (- n 1)))))]))
(define (deep n)
(cond
[(zero? n) 0]
[else
(quasiquote ((unquote n) (unquote (deep (- n 1)))))])))
(deep 8)
]
Or even to cheaply construct expressions programmatically. (Of course, 9 times out of 10,
you should be using a @seclink["macros"]{macro} to do this
(the 10th time being when you're working through
a textbook like @hyperlink["http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/"]{PLAI}).)
@examples[(define (build-exp n)
(add-lets n (make-sum n)))
(eval:alts
(define (add-lets n body)
(cond
[(zero? n) body]
[else
(#,qq
(let ([(#,uq (n->var n)) (#,uq n)])
(#,uq (add-lets (- n 1) body))))]))
(define (add-lets n body)
(cond
[(zero? n) body]
[else
(quasiquote
(let ([(unquote (n->var n)) (unquote n)])
(unquote (add-lets (- n 1) body))))])))
(eval:alts
(define (make-sum n)
(cond
[(= n 1) (n->var 1)]
[else
(#,qq (+ (#,uq (n->var n))
(#,uq (make-sum (- n 1)))))]))
(define (make-sum n)
(cond
[(= n 1) (n->var 1)]
[else
(quasiquote (+ (unquote (n->var n))
(unquote (make-sum (- n 1)))))])))
(define (n->var n) (string->symbol (format "x~a" n)))
(build-exp 3)]
The @racket[unquote-splicing] form is similar to @racket[unquote], but
its @racket[_expr] must produce a list, and the
@racket[unquote-splicing] form must appear in a context that produces
@ -35,6 +92,46 @@ is spliced into the context of its use.
`(1 2 ,@(list (+ 1 2) (- 5 1)) 5))
]
Using splicing we can revise the construction of our example expressions above
to have just a single @racket[let] expression and a single @racket[+] expression.
@examples[(eval:alts
(define (build-exp n)
(add-lets
n
(#,qq (+ (#,(racket unquote-splicing)
(build-list
n
(λ (x) (n->var (+ x 1)))))))))
(define (build-exp n)
(add-lets
n
(quasiquote (+ (unquote-splicing
(build-list
n
(λ (x) (n->var (+ x 1))))))))))
(eval:alts
(define (add-lets n body)
(#,qq
(let (#,uq
(build-list
n
(λ (n)
(#,qq
[(#,uq (n->var (+ n 1))) (#,uq (+ n 1))]))))
(#,uq body))))
(define (add-lets n body)
(quasiquote
(let (unquote
(build-list
n
(λ (n)
(quasiquote
[(unquote (n->var (+ n 1))) (unquote (+ n 1))]))))
(unquote body)))))
(define (n->var n) (string->symbol (format "x~a" n)))
(build-exp 3)]
If a @racket[quasiquote] form appears within an enclosing
@racket[quasiquote] form, then the inner @racket[quasiquote]
effectively cancels one layer of @racket[unquote] and