Re: Expansion problem
Philip McGrath <philip-HuI0B06iylScIzJqBAPImwC/[email protected]>
| Newsgroups | gmane.comp.lang.racket.user,gmane.lisp.scheme.plt |
|---|---|
| Message-ID | <CAH3z3gaHRBv9Obn2qTQt51Lynh86D2=Kx1AhCXqYjedytmMWXA@mail.gmail.com> |
The bindings of a `let`/`let*`/etc. form can be generated by
macro-expansion, but the binding pairs are not expressions: a
transformer/macro binding for the left-hand-side identifier doesn't trigger
macro expansion. This is a good thing, because otherwise you wouldn't be
able to let-bind names defined as macros. Binding pairs for a let-like form
have to be generated by the expansion step that introduces the let.
Here is an example of a macro that introduces a let, along with an example
of why extra expansion steps triggered by the left-hand-sides of let-like
forms would be a problem:
(define-syntax let2
(syntax-rules ()
[(_ lhs1 rhs1 lhs2 rhs2 body0 body ...)
(let ([lhs1 rhs1]
[lhs2 rhs2])
body0 body ...)]))
(= (let2 x 1
y 2
(+ x y))
(let ([let2 +])
(let2 1 2)))
Some other notes:
- I see that you have `(do* "ending")` expand to `(if #f #f)`, which is
a syntax error in Racket.
- Using strings to dispatch to your additional cases will work, but it
would be most idiomatic to use Racket's keywords
- This macro would be much more easily written with `syntax-case` than
`syntax-rules`, or better yet with `syntax-parse`, which would give you
better error reporting. Also, its "syntax class" feature supports a style
of writing very much like what you're trying to do with your extra cases.
In fact, the introduction in the documentation (
http://docs.racket-lang.org/syntax/stxparse-intro.html) walks through
the implementation of a let macro, including support for let-loops, which I
think would show you much of what you need to write your `do*`.
-Philip
On Wed, May 30, 2018 at 4:33 PM, Jean-Michel HUFFLEN <jmhuffle-qPpMuP/[email protected]>
wrote:
> Hello, Racket's friends!
>
> I'm trying to define the "do*" special form of Common Lisp by a Racket
> macro. Let us recall that "do*" is analogous to "do", but the bindings and
> updating of variables are done sequentially. A simple example where "do"
> and "do*" do not yield the same result could be:
>
> (do* ((i 0 (+ i 1))
> (j 0 (+ i j 1)))
> ((= i 10) (+ i j))
> (write (cons i j))
> (newline))
>
> In addition, I allow bindings like (var init step) and (var init),
> processed like (var init var). If I define "do*" as follows:
>
> (define-syntax do*
> (syntax-rules ()
> ((do* ((var init step ...) ...) (test expr-0 ...) body-expr-0 ...)
> (let* ((var init) ...)
> (let loop ()
> (if test
> (do* "ending" expr-0 ...)
> (begin
> body-expr-0 ... (do* "step" var step ...) ... (loop))))))
> ((do* "ending") (if #f #f))
> ((do* "ending" expr-0) expr-0)
> ((do* "ending" expr-0 ...) (begin expr-0 ...))
> ((do* "step" var) #f)
> ((do* "step" var step) (set! var step))))
>
> that works, but I don't like this solution because of side effects. If I
> try:
>
> (define-syntax do*
> (syntax-rules ()
> ((do* ((var init step ...) ...) (test expr-0 ...) body-expr-0 ...)
> (let* ((var init) ...)
> (let loop ((var var) ...)
> (if test
> (do* "ending" expr-0 ...)
> (begin
> body-expr-0 ...
> (let* ((do* "step" var step ...) ...) (loop var ...)))))))
> ((do* "ending") (if #f #f))
> ((do* "ending" expr-0) expr-0)
> ((do* "ending" expr-0 ...) (begin expr-0 ...))
> ((do* "step" var) (var var))
> ((do* "step" var step) (var step))))
>
> that results in the following error:
>
> let*: bad syntax (not an identifier and expression for a binding) in: (do*
> "step" i (+ i 1))
>
> Please, does it mean that the bindings of a "let*" special form cannot
> be the result of a macro expansion? Many thanks in advance,
>
> J.-M. Hufflen
>
>
> ----------------------------------------------------------------
> This message was sent using IMP, the Internet Messaging Program.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> For more options, visit https://groups.google.com/d/optout.
>
--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
For more options, visit https://groups.google.com/d/optout.