1

在 Gambit Scheme 中,如果我编译文件,我似乎无法在另一个宏的定义中调用宏。这是一个人为的例子:

;;;; 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

但是,如果我在解释器中加载具有(include ...)特殊形式的文件,它就可以工作

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

有谁知道这里发生了什么?我可以说服 Gambit 让我在编译文件中另一个宏的定义中使用 w/gensyms 吗?

4

2 回答 2

0

这是一个阶段性问题。您希望 w/gensyms 的定义在后续宏的主体中可用。这可以通过一个 for-syntax 宏来实现,该宏在语法扩展时强制评估宏定义:

(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)))

如果您希望宏在其他宏定义和非宏定义代码中都可用,您可以使用它来代替:

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

对于这个特定示例,由于您在单个位置使用宏,您可以这样做:

(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)))))

解决相位问题的一种相关方法是将 w/gensyms 和其他宏的定义放在文件“macros.scm”中并执行以下操作:

(define-macro (compose-macro f g)

  (include "macros.scm")

  (w/gensyms (x)
    `(lambda (,x) (,f (,g ,x)))))
于 2017-05-09T05:55:47.203 回答
0

这很可能与阶段有关。

尝试这个:

放入w/gensyms一个文件a.scm,放入compose-macro一个导入a.scm的文件b.scm。

于 2017-05-07T21:02:32.993 回答