Hacker News new | past | comments | ask | show | jobs | submit login
The Underbelly of Racket Macro Basics (jeapostrophe.github.io)
39 points by nickmain on July 22, 2013 | hide | past | favorite | 6 comments



I've been trying to learn Racket macros but articles like this make me feel like I should just give up. For example, in arc a macro looks like this:

  (mac awhen (expr . body)
    `(let it ,expr (if it (do ,@body))))
I can understand that, and start making macros and going about my business. The Racket guys (e.g. Eli and Jay) write macros that look like this:

  (require (lib "stxparam.ss" "mzlib"))
  (define-syntax-parameter it
    (lambda (stx)
      (raise-syntax-error #f "can only be used inside `if'" stx)))
  (define-syntax if*
    (syntax-rules ()
      [(if*) (void)]
      [(if* X) X]
      [(if* C X more ...)
       (let ([b C])
         (if b
           (syntax-parameterize ([it (make-rename-transformer #'b)]) X)
           (if* more ...)))]))
Or like this:

  (define-syntax (123-list stx)
  (define middle-x-stx (second (syntax->list stx)))
  (define x-id (syntax-e middle-x-stx))
  (define new-ctxt-stx (datum->syntax #f 'new-ctxt))
  (datum->syntax
   new-ctxt-stx
   (list (datum->syntax #'123-list 'let)
         (list (list x-id (datum->syntax #'123-list 3)))
         (list (datum->syntax #'123-list '#%app)
               (datum->syntax #'123-list 'list)
               (datum->syntax #'123-list x-id)
               middle-x-stx
               x-id))))
They have reasonable objections to arc-style macros, but I feel like they are overly academic and not relevant to the programming problems that I want to address. I want to eliminate boilerplate, and I'm willing to take the limitations of arc-style macros because they are so much easier to understand.


Your code (`when` that binds `it`) translates to:

  (define-syntax (awhen stx)
    (syntax-case stx ()
      ((_ expr body ...)
       (with-syntax ((it (datum->syntax stx 'it)))
         #`(let ((it expr))
             (when it body ...))))))
I find it a bit hairy, but mostly sane. It's all about being hygienic. Notice how you explicitly place the `it` identifier into the caller's context but keep the usual let and when?


If you're trying to get things done in Racket, just learn define-syntax-rule [1] and syntax/parse [2].

You also picked as your example the one thing unhygienic macros are good at. Even in arc.arc, most macros start with (w/uniq (let boilerplate like:

  (mac or args
    (and args
         (w/uniq g
           `(let ,g ,(car args)
              (if ,g ,g (or ,@(cdr args)))))))
In my code breaking hygiene is the exception, not the common case, and my Racket macros are usually shorter than the equivalent arc macros.

  [1]: http://docs.racket-lang.org/guide/pattern-macros.html
  [2]: http://docs.racket-lang.org/syntax/stxparse.html


This is Jay. Arc macros are like define-syntax-rule macros in Racket. dsr is great for lots of things, but sometimes you need more power.

In any case, this post is really about what's going on in the pattern matching and macro template underbelly, and not really a recommendation for how to program macros.


> I'm willing to take the limitations of arc-style macros because they are so much easier to understand.

Then don't use scheme, hygienic macros has always been a major difference between a scheme and a lisp.


I just noticed Realm of Racket in my local bookstore a few days ago. Haven't had time to peruse, but looks good, a dozen pages on macros

http://nostarch.com/realmofracket (download a chapter, index and ToC)

_______________________________________

also, on the openJDK list, they're looking at Clements/Felleisen's tail call writeup from 2004

http://mail.openjdk.java.net/pipermail/mlvm-dev/2013-July/00...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: