1

In Gambit Scheme, I can't seem to invoke a macro in the definition of another macro if I compile the file. Here is a contrived example:

;;;; example.scm

(define-macro (w/gensyms gs body)
  `(let ,(map (lambda (g) `(,g (gensym ',g)))
              gs)
     ,body))

(define-macro (compose-macro f g)
  (w/gensyms (x)
    `(lambda (,x) (,f (,g ,x)))))

(define my-cadr
  (lambda (x)
    ((compose-macro car cdr) x)))

;; $ gsc example.scm
;; *** ERROR IN #<procedure #2> -- Unbound variable: w/gensyms

However, if I load the file with the (include ...) special form in the interpreter, it works

$ gsi
> (include "example.scm")
> (pp my-cadr)
(lambda (x) ((lambda (#:x0) (car (cdr #:x0))) x))

Does anyone know what is going on here? Can I convince Gambit to let me use w/gensyms in the definition of another macro in a compiled file?

scpayson
  • 192
  • 8

2 Answers2

0

This is most likely related to phases.

Try this:

Put w/gensyms in a file a.scm and put compose-macro in a file b.scm that imports a.scm.

soegaard
  • 30,661
  • 4
  • 57
  • 106
  • import how? According to the gambit manual I need to use `include` to splice in macro definitions. – scpayson May 07 '17 at 21:38
  • If I understand correctly Gambit uses a module system called Black Hole: http://dynamo.iro.umontreal.ca/wiki/images/3/30/Black_Hole_Core.pdf – soegaard May 08 '17 at 03:51
0

This is a phasing problem. You want the definition of w/gensyms to be available in the body of subsequent macros. This can be achieved with a for-syntax macro that forces the evaluation of the macro definition at syntax expansion time:

(define-macro (for-syntax . body)
  (eval `(begin ,@body))
  `(begin))

(for-syntax
 (define-macro (w/gensyms gs body)
   `(let ,(map (lambda (g) `(,g (gensym ',g)))
               gs)
      ,body)))

If you want the macro to be available both from within other macro definitions and within non-macro definition code you can use this instead:

(define-macro (for-syntax . body)
  (eval `(begin ,@body))
  `(begin ,@body))

For this specific example, since you are using the macro at a single place, you could have done this:

(define-macro (compose-macro f g)

   (define-macro (w/gensyms gs body)
     `(let ,(map (lambda (g) `(,g (gensym ',g)))
                 gs)
        ,body))

  (w/gensyms (x)
    `(lambda (,x) (,f (,g ,x)))))

A related approach to address phasing issues is to put the definition of w/gensyms and other macros in the file "macros.scm" and do:

(define-macro (compose-macro f g)

  (include "macros.scm")

  (w/gensyms (x)
    `(lambda (,x) (,f (,g ,x)))))
feeley
  • 71
  • 4