如何使用Racket宏定义函数? [英] How do I define functions using Racket macros?
问题描述
我正在尝试编写一个宏,该宏定义具有相关功能的特殊数据结构类.
I am trying to write a macro that defines a special class of data structure with associated functions.
我知道这是可能的;它是在核心语言本身中多次执行的.
I know this is possible; it is done multiple times in the core language itself.
作为一个具体示例,我将如何在Scheme本身中定义define-struct
宏.它需要创建make-struct
,struct-<<field>>
等函数.
As a specific example, how would I define the define-struct
macro in Scheme itself. It needs to create make-struct
, struct-<<field>>
, etc functions.
我尝试使用define
进行此操作,但是,这仅在宏的词法范围内定义了函数.
I tried doing this using define
, however, this only defines the function in the macro's lexical scope.
我该如何在宏中实际定义一个函数?
How can I actually define a function in a macro?
推荐答案
答案的关键是datum->syntax
.基本思想是要获取一些随机数据并将其转换为语法-在这种情况下,请将符号转换为标识符.标识符基本上是一个带有一些词汇信息的符号,这些词汇信息(非常粗略地)表明了其绑定方式.使用datum->syntax
,您可以精确地做到这一点:它期望从其复制绑定的位置使用现有语法,并获得语法包装中包含的值的数据(此处为符号).
The key for an answer is datum->syntax
. The basic idea is that you want to take some random data and turn it into a syntax -- in this case, turn a symbol into an identifier. An identifier is basically a symbol with some lexical information that (very roughly) indicates how it is bound. Using datum->syntax
you can do exactly that: it expects an existing piece of syntax which is where it copies the binding from, and a datum (a symbol here) which is the value that is contained in the syntax wrapper.
下面是一个使用此工具演示类似define-struct
的工具的示例:
Here's an example that demonstrates a define-struct
-like tool using this:
#lang scheme
;; implements a defstruct-like macro that uses association lists
(define-syntax (defstruct-lite stx)
(syntax-case stx ()
[(defstruct-lite name field ...)
(let ([make-id
(lambda (template . ids)
(let ([str (apply format template (map syntax->datum ids))])
(datum->syntax stx (string->symbol str))))])
(with-syntax ([make-name (make-id "make-~a" #'name)]
[name? (make-id "~a?" #'name)]
[(arg ...) (generate-temporaries #'(field ...))]
[(name-field ...)
(map (lambda (f) (make-id "~a-~a" #'name f))
(syntax->list #'(field ...)))])
#'(begin
(define (make-name arg ...) (list 'name (cons 'field arg) ...))
(define (name? x) (and (pair? x) (eq? 'name (car x))))
(define (name-field x)
(and (name? x) (cdr (assq 'field (cdr x)))))
...)))]))
这是一个使用它的示例:
And here's an example of using it:
(defstruct-lite point x y)
(point-y (make-point 1 2))
这篇关于如何使用Racket宏定义函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!