Racket - 如何定义一个可以在语法转换器和普通代码中使用的函数?

Dev*_*XYS 1 macros hygiene racket

我正在使用语法转换器在 Racket 中定义宏。我想创建一些辅助函数来帮助我操作语法。但是,我在语法转换器外部定义的函数在语法转换器内部不可用。例如,在下面的代码中

(define (my-function x) (+ x 1))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))
Run Code Online (Sandbox Code Playgroud)

我收到错误“我的函数:在阶段:1 处引用未绑定标识符;变压器环境”。

经过一番搜索后,我能够编写以下代码,以便my-function在语法转换器中可用。

(begin-for-syntax
  (define (my-function x) (+ x 1)))
(provide (for-syntax my-function))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))
Run Code Online (Sandbox Code Playgroud)

但问题是,my-function这次在语法转换器之外不可用。有时我想在普通代码中检查这些辅助函数,因此我需要能够从语法转换器的内部和外部调用它,就像 function 一样cadr。我怎样才能做到这一点?

我知道我的问题与 Racket 的语法模型有关,特别是“阶段级别”的概念,但我从来没有真正理解它。如果您能提供一些易于理解的教程来解释它,我将更加感激。

Sor*_*ase 5

一种常见的方法是定义要在另一个(子)模块中跨阶段共享的函数。然后,require就两次了。

#lang racket

(module common racket
  (provide my-function)
  (define (my-function x) (+ x 1)))

(require 'common
         (for-syntax 'common))

(define-syntax my-macro
  (lambda (stx)
    (datum->syntax stx (my-function (cadr (syntax->datum stx))))))

(my-function 1)
(my-macro 123)

Run Code Online (Sandbox Code Playgroud)