[Aggregate reply, since you got replies from all over the place...] On Sun, Jan 18, 2015 at 7:49 PM, Peter Samarin <petrsama...@gmail.com> wrote: > Hi all, > > I was working through chapter 16 of "land of lisp" and there is (at > that point) a buggy split macro defined like this: > > (defmacro split (val yes no) > `(if ,val > (let ((head (car ,val)) > (tail (cdr ,val))) > ,yes) > ,no)) > > Here is my version of the equivalently buggy Racket counterpart: > [...]
As Neil said, using `eval' is almost always a bad idea. A genral rule of thumb is that if you're not sure whether it's a bad idea, then it is. (Seriously.) If you really want an unhygienic Racket translation of that macro, then: (require compatibility/defmacro) and then you can use the above macro definition as-is. But it is unhygienic, which is still a problem. On Sun, Jan 18, 2015 at 8:04 PM, Jon Zeppieri <zeppi...@gmail.com> wrote: > Breaking hygiene with `syntax-case`: > > (define-syntax (split stx) > (syntax-case stx () > ([split val yes no] > (let ([head-stx (datum->syntax stx 'head)] > [tail-stx (datum->syntax stx 'tail)]) > ...)))) Yes, you can do that -- it's kind of similar to what the compatipility `defmacro' will do for you -- but it's just as bad. The thing is that Racket has *identifiers*, whereas in Lisp you have plain symbols. The difference is that an identifier is kind of like a symbol + its lexical scope. If you're coming from common lisp, then you can think about it as if each newly nested scope has symbols in a new (anonymous-ish) package. Keeping that in mind, read http://barzilay.org/misc/stxparam.pdf to see what's wrong with unhygienic macros. On Sun, Jan 18, 2015 at 8:31 PM, Neil Van Dyke <n...@neilvandyke.org> wrote: > * Just doing it as a procedure that takes closures for the `yes`and > `no` arguments (with the `yes` one taking arguments for `head` and > `tail`). That works -- it's often a way to keep most of the functionality in a function, and then have a macro that deals with the syntax. > * Doing it as syntax, but having the user of the extension define the > . (This might seem overkill, but maybe that's because that's > because the original macro is already overkill.) Assuming that you're talking about having the user of the macro provide the identifiers -- it's a common sentiment, but it doesn't work either. It breaks when you want to use macros in macros (which is exactly where the unhygienic solutions break too; see the above PDF for an explanation). On Sun, Jan 18, 2015 at 8:19 PM, J. Ian Johnson <i...@ccs.neu.edu> wrote: > You're better off defining head and tail as syntax parameters and > defining your macro with the more hygienic syntax-parameterize using > rename transformers. [...] That's the best approach, but since it's still looks as a confusing issue as ever, it's worth to make this explicit and provide the bits that Ian skipped: #lang racket (require racket/stxparam) (define-syntax-parameter head (lambda (s) (raise-syntax-error 'head "can only be used in a `split'" s))) (define-syntax-parameter tail (lambda (s) (raise-syntax-error 'tail "can only be used in a `split'" s))) (define-syntax-rule (split val yes no) (if (empty? val) no (let ([h (car val)] [t (cdr val)]) (syntax-parameterize ([head (make-rename-transformer #'h)] [tail (make-rename-transformer #'t)]) yes)))) Now you can fix the problem of evaluating the value multiple times in a similar way to LoL: #lang racket (require racket/stxparam) (define-syntax-parameter head (lambda (s) (raise-syntax-error 'head "can only be used in a `split'" s))) (define-syntax-parameter tail (lambda (s) (raise-syntax-error 'tail "can only be used in a `split'" s))) (define-syntax-rule (split val yes no) (let ([x val]) (if (empty? x) no (let ([h (car x)] [t (cdr x)]) (syntax-parameterize ([head (make-rename-transformer #'h)] [tail (make-rename-transformer #'t)]) yes))))) And that works fine. -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life! ____________________ Racket Users list: http://lists.racket-lang.org/users