我记得我在某个地方看过它不是一个宏,并且内置于核心语言中。这样的事情,我不确定,因为我不再记得从哪里读到它。那么,struct
是否是Racket中的一个宏?如果没有,为什么它被内置到核心语言中?
答案 0 :(得分:3)
一个宏; 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
功能查找源代码(如果有)。
答案 1 :(得分:3)
当我之前回答时,看起来我误解了这个问题。所以这是对这个问题的答案:
结构是内置的和原始的;它们是实施的基础。事实上,大约在2007年,马修弗拉特评论说,在PLT计划中(因为当时知道球拍),从某种意义上讲,一切都是结构:
>在2007年5月31日星期四16:45:25 -0700,YC写道:
>出于好奇 - PLT计划实际上使用结构作为基础 >复合类型,即在struct顶部实现闭包/等。我想到它的方式,一切都是结构,但有些东西使用了 特殊情况表示,因为它们足够重要。 (该 极端情况是一个固定的例子。)
但同样有效的答案是:不,并非所有化合物类型都使用 与结构构造函数中的值相同的表示形式。
- Source。
答案 2 :(得分:0)
除了usepla的好答案,我想补充一下:
在Racket文档中,“蓝框”的右上角有一个词组,例如procedure
或syntax
。 struct
代表syntax
。
如果你考虑struct
做了什么,除了别的以外,它还定义了从结构名称派生的命名函数。因此(struct foo (a b))
将定义foo?
谓词和访问者foo-a
,foo-b
。普通函数不能定义像这样的新命名事物,因此,它必须是宏。
答案 3 :(得分:0)
通读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)在实际版本中,大多数代码都处理可用于结构定义的属性。实际版本还需要处理任意数量的变量和其他形式,默认值等。