[racket] One define to rule them all

From: Neil Toronto (neil.toronto at gmail.com)
Date: Fri Nov 12 18:40:57 EST 2010

In internal definition contexts, I've been using the following macro to 
define everything but functions:

(define-syntax (def stx)
   (syntax-case stx (values)
     [(_ x e0 e ...)
      (identifier? #'x)
      (syntax/loc stx
        (define x (let () e0 e ...)))]
     [(_ (values x ...) e0 e ...)
      (andmap identifier? (syntax->list #'(x ...)))
      (syntax/loc stx
        (define-values (x ...) (let () e0 e ...)))]
     [(_ (values pat ...) e0 e ...)
      (syntax/loc stx
        (match-define (list pat ...)
                      (call-with-values (lambda () e0 e ...) list)))]
     [(_ pat e0 e ...)
      (syntax/loc stx
        (match-define pat (let () e0 e ...)))]))


So these do the obvious things:

     (def a 4)
     (def (values) (values))
     (def (values b c) (values 4 5))
     (def (values (list d e) f)
       (values (list 4 5) 6))

Common cases like (def x:id e ...+) and (def (values x:id ...) e ...+) 
expand to the most direct define-like form. (It avoids `match-define' 
because `match-define' 1) always binds a failure thunk; and 2) forces 
multiple values to be converted to lists.)

With `def', it's easier to recognize a sequence of definitions leading 
up to a computation buried inside a conditional branch. For example, 
instead of:

     (cond ...
           [(the-condition? z-sig)
            (define x (compute-x z))
            (match-define (foo y-bar y-baz) y)
            (define-values (a b) (get-some-values x y-bar))
            (the-computation x y-baz a b)] ...)

I have:

     (cond ...
           [(the-condition? z-sig)
            (def x (compute-x z))
            (def (foo y-bar y-baz) y)
            (def (values a b) (get-some-values x y-bar))
            (the-computation x y-baz a b)] ...)

It's hard to miss all the `def's lined up in the same column.

Have I left anything out? Does anybody else think it's awesome/useful? 
Hideous?

Neil T

(It's a shame it can't do functions, but there's no way to tell whether 
(def (foo y-bar y-baz) ...) is intended to match a foo struct or define 
a foo function. Also, optional parameters and struct matching look the 
same. I wrote a `defun' macro that solves the latter problem - it even 
does currying and keywords - but I can't say that I like it yet.)



Posted on the users mailing list.