我正在尝试编写一个像行星定义一样的宏行为,但是以某种方式处理完全扩展的球拍程序(为了简单起见,在下面的例子中):
(define-syntax (define/expand stx)
(syntax-case stx ()
[(_ (head args ...) body body-rest ...)
(let* ([define/racket (syntax/loc stx (define (head args ...) body body-rest ...))]
[fully-expanded (local-expand define/racket 'top-level (list))])
fully-expanded)]
[(_ id expr) (syntax/loc stx (define id expr))]))
除非满足递归定义,否则一切都很好:
(define/expand (sum n)
(if (<= n 0)
0
(+ n (sum (- n 1)))))
运行它会引发错误
sum:模块中的未绑定标识符:sum
指向 sum
的调用(不是定义) . 显然,本地扩展器没有捕获 sum
的定义 . 我尝试了一种简单的方法来修复它:创建新的本地定义上下文并将 head
绑定到其中:
(define-syntax (define/expand stx)
(syntax-case stx ()
[(_ (head args ...) body body-rest ...)
(let* ([ctx (syntax-local-make-definition-context)] ; <- These two lines added
[_ (syntax-local-bind-syntaxes (list #'head) #f ctx)] ; <--/
[define/racket (syntax/loc stx (define (head args ...) body body-rest ...))]
[fully-expanded (local-expand define/racket 'top-level (list) ctx)])
fully-expanded)]
[(_ id expr) (syntax/loc stx (define id expr))]))
它解决了问题(本地扩展成功地将过程扩展为 define-values
),但创建了另一个:
module:用于定义的out-of-context标识符:sum
指向总和的定义 . 原因可能是扩展器将标识符绑定到 ctx
中的一个而不是当前上下文中的 head
.
直觉上它似乎不是一个罕见的问题,但我找不到网络上的解决方案 . 我以为我应该以某种方式使用 local-expand/capture-lifts
和 syntax-local-lift-expression
,但我不会't get how to use it properly. Could someone clarify what'继续和/或提示如何修复它?
1 回答
让我们在顶级(repl)尝试你的第一个程序:
然后在repl中:
这表明您的程序在顶级工作 .
同一方法在模块上下文中不起作用的原因是
#%module-begin
在扩展表达式之前使用表单的部分扩展来检测定义 . 换句话说,define / expand必须告诉#%module-begin
它扩展为sum
的定义,但必须延迟使用local-expand
,直到#%module-begin
检测到模块级别的所有绑定标识符 .这表明了两步法:
在这里查看更多:https://groups.google.com/d/msg/racket-users/RB3inP62SVA/54r6pJL0wMYJ