【发布时间】:2014-01-22 18:50:18
【问题描述】:
我记得我在某处读到它不是宏,而是内置于核心语言中。类似的东西,我不确定,因为我已经不记得从哪里读到它了。 struct 是 Racket 中的宏吗?如果不是,为什么要内置在核心语言中?
【问题讨论】:
-
Racket 中很少有句法形式不是宏:非宏的完整列表在这里:docs.racket-lang.org/reference/…
标签: racket
我记得我在某处读到它不是宏,而是内置于核心语言中。类似的东西,我不确定,因为我已经不记得从哪里读到它了。 struct 是 Racket 中的宏吗?如果不是,为什么要内置在核心语言中?
【问题讨论】:
标签: racket
一个宏; struct.rkt有
(define-syntax (struct stx)
(define (config-has-name? config)
(cond
[(syntax? config) (config-has-name? (syntax-e config))]
[(pair? config) (or (eq? (syntax-e (car config)) '#:constructor-name)
(eq? (syntax-e (car config)) '#:extra-constructor-name)
(config-has-name? (cdr config)))]
[else #f]))
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ id super-id fields . config)
(and (identifier? #'id)
(identifier? #'super-id))
(if (not (config-has-name? #'config))
(syntax/loc stx
(define-struct/derived orig (id super-id) fields #:constructor-name id . config))
(syntax/loc stx
(define-struct/derived orig (id super-id) fields . config)))]
[(_ id fields . config)
(identifier? #'id)
(if (not (config-has-name? #'config))
(syntax/loc stx
(define-struct/derived orig id fields #:constructor-name id . config))
(syntax/loc stx
(define-struct/derived orig id fields . config)))]
[(_ id . rest)
(identifier? #'id)
(syntax/loc stx
(define-struct/derived orig id . rest))]
[(_ thing . _)
(raise-syntax-error #f
"expected an identifier for the structure type name"
stx
#'thing)]))))
在 Racket IDE 中,您可以使用 Open Defining File 函数来定位源代码(如果有的话)。
【讨论】:
define-struct/derived。新问题:define-struct/derived 是宏还是原语?
struct 一路追踪。你已经到达define-struct/derived,这也是一个定义在define-struct.rkt文件中的宏。
make-struct-type 的过程,它在struct.c 中定义。我猜这意味着它是核心语言中的原始语言。
我之前回答的时候好像误解了这个问题。所以这里是对这个问题的答案:
结构是内置的和原始的;它们是实施的基础。事实上,大约在 2007 年,Matthew Flatt 评论说,在 PLT Scheme(当时已知的 Racket)中,从某种意义上说,一切都是结构:
> 2007 年 5 月 31 日星期四 16:45:25 -0700,YC 写道:
> 出于好奇 - PLT 方案实际上是否使用 struct 作为基础
> 复合类型,即在结构之上实现闭包/等。在我看来,一切都是结构,但有些东西使用 特殊情况表示,因为它们足够重要。 (这 极端情况是一个固定数字)。
但同样有效的答案是:不,并非所有复合类型都使用 与结构构造函数中的值相同的表示。
-- Source.
【讨论】:
struct foo 创建了类型检查函数foo?,而将integer?、boolean? 等视为根本上没有什么明显的优势不同种类的功能?
除了usepla的精彩回答,我想补充一下:
在 Racket 文档中,“蓝色框”的右上角有一个短语,例如 procedure 或 syntax。对于struct,它表示syntax。
如果您考虑 struct 的作用,除其他外,它定义了从结构名称派生的命名函数。所以(struct foo (a b)) 将定义一个foo? 谓词和访问器foo-a、foo-b。一个普通的函数不能像这样定义新的命名事物,所以它必须是一个宏。
【讨论】:
通读define-struct.rkt中的实现代码,如果你想手动做同样的事情,下面的代码是它正在做的一个大大简化的版本。
(define-syntax (struct stx)
;
; Function that creates compound names using syntax objects
(define (make-name id . parts)
(datum->syntax
id
(string->symbol
(apply string-append
(map (lambda (p)
(if (syntax? p)
(symbol->string (syntax-e p))
p))
parts)))
id))
;
(syntax-case stx ()
;
; parse the input and extract the name and variable
; this version uses only one variable for simplicity (3)
[(_ id avar)
;
; guard to ensure we have an identifier
(identifier? #'id)
;
; Create the names (1)
(let ((? (make-name #'id #'id "?"))
(v (make-name #'id #'id "-" #'avar)))
; Generate code to define the various functions associated with
; the new struct (2)
#`(begin
(define id (lambda (vx) (list id vx)))
(define #,? (lambda (x) (eq? (car x) id)))
(define #,v (lambda (x) (second x)))))]
))
1) 我们必须创建我们将定义的名称:但我们需要使用语法对象来这样做
2) 我们生成的代码将定义与全局命名空间中的新对象关联的所有函数
3) 在实际版本中,大部分代码都处理可用于结构定义的属性。真实版本还需要处理任意数量的变量和替代形式、默认值等...
【讨论】: