Common Lisp-style macros in Racket

Today I put myself together and read a couple of sections of Racket documentation. Now I finally know how to implement Common Lisp-style macros in Racket. I'm still not 100% sure it will work exactly as expected but common cases work right.

Here it is:

(define-syntax define-macro
  (syntax-rules ()
   ((_ name fn)
    (define-syntax (name stx)
      (datum->syntax stx (apply fn (cdr (syntax->datum stx))))))))

(define-macro mac
  (lambda (sig . body)
    (cond ((symbol? sig) `(define-macro ,sig ,@body))
          ((pair? sig)   `(define-macro ,(car sig) (lambda ,(cdr sig) ,@body)))
          (else           (error "wrong use of mac")))))

This will give you macro-defining macro mac as in Paul Graham's Arc, except that I defined it in a Scheme way. You will easily figure out how to use it from this example:

(mac (with var exp . body)
    `((lambda (,var) ,@body) ,exp))

(with a 2 (+ a  4)) ; => 6

UPD: In case you want to write a macro that makes use of a function defined in the same file this will not work. But it can easily be fixed by defining this function with define-with-syntax as described here.

Data structures on functional position

Hardly anyone would disagree that Scheme's vector-set!, vector-ref and others make code fat and hard to read.

I like the way Arc's handles this. If a hash table is placed on the functional position this is treated as hash-ref.

To make this possible in Guile one could pack a hash table into a closure meaning make it a function of one argument (or 2 args for hash-set!).

But that way they won't be distinguishable from the normal functions. Procedure? will state that vectors are procedures while hash-table? will return false.

There is a trick to patch a typesystem of Guile. One can write a new operator λ which would return a function that first checks it's args for being a type request, and if it's not then work according to the definition:

(define (type-request? x) 
  (and (pair? x) 
      (eq? (car x) #:type)))

(mac (λ parms . body) 
  (w/uniq (gxs) 
    `(lambda ,gxs 
       (if (type-request? ,gxs) 'proc 
          (apply (lambda ,parms ,@body) ,gxs))))

Having that hash table constructor can create functions that being passed #:type keyword return 'table for example. That way one will be able to rewrite the predicates procedure? and hash-table? to react properly on new objects.

It's even possible (and easy) to write Arc-style functions annotate, type and rep.