Racket:局部扩展递归定义

Racket:局部扩展递归定义,racket,metaprogramming,Racket,Metaprogramming,我试图编写一个宏,其行为与racketdefine类似,但以某种方式处理完全扩展的racket过程(为了简单起见,在下面的示例中进行扩展): 除非满足递归定义,否则一切正常: (define/expand (sum n) (if (<= n 0) 0 (+ n (sum (- n 1))))) 它解决了这个问题(local expanded成功地将过程扩展为定义值),但创建了另一个: 模块:中定义的上下文外标识符:sum 指出和的定义。原因可能是扩展器将标识符

我试图编写一个宏,其行为与racketdefine类似,但以某种方式处理完全扩展的racket过程(为了简单起见,在下面的示例中进行扩展):

除非满足递归定义,否则一切正常:

(define/expand (sum n)
  (if (<= n 0)
      0
      (+ n (sum (- n 1)))))
它解决了这个问题(local expanded成功地将过程扩展为
定义值
),但创建了另一个:

模块:中定义的上下文外标识符:sum

指出和的定义。原因可能是扩展器将标识符绑定到
ctx
中的标识符,而不是当前上下文中的
head


直觉上,这似乎不是一个罕见的问题,但我无法通过网络找到解决方案。我想我应该以某种方式使用
本地扩展/捕获提升
语法本地提升表达式
,但我不知道如何正确使用它。有人能解释一下发生了什么事情和/或给出一个如何修复的提示吗?

让我们尝试一下顶级(repl)中的第一个程序:

然后在repl中:

Welcome to DrRacket, version 6.6.0.3--2016-07-28(-/f) [3m].
Language: racket, with debugging [custom]; memory limit: 1024 MB.
> (define/expand (sum n)
  (if (<= n 0)
      0
      (+ n (sum (- n 1)))))
.#<syntax:3:2 (define-values (sum) (lambda ...>
> (sum 5)
15

更多信息请参见此处:

哇,好把戏,非常感谢!它还回答了其他一些问题。另一个有时很有用的技巧是:在绑定未绑定变量的lambda上调用
local expand
,然后模式匹配结果以取出主体。
(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))]))
#lang racket
(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))]))
Welcome to DrRacket, version 6.6.0.3--2016-07-28(-/f) [3m].
Language: racket, with debugging [custom]; memory limit: 1024 MB.
> (define/expand (sum n)
  (if (<= n 0)
      0
      (+ n (sum (- n 1)))))
.#<syntax:3:2 (define-values (sum) (lambda ...>
> (sum 5)
15
#lang racket

(define-syntax (delay-expansion stx)
  (syntax-case stx ()
    [(_delay-expansion more ...)
     (let ([fully-expanded (local-expand #'(lambda () more ...) 'module (list))])
       (display fully-expanded)
       fully-expanded)]))

(define-syntax (define/expand stx)
  (syntax-case stx ()
    [(_ (head args ...) body body-rest ...)
     (syntax/loc stx
       (define (head args ...)
         ((delay-expansion
           body body-rest ...))))]
    [(_ id expr)
     (syntax/loc stx
       (define id expr))]))


(define/expand (sum n)
  (if (<= n 0)
      0
      (+ n (sum (- n 1)))))

(sum 5)