【问题标题】:Is struct a macro in Racket?结构是球拍中的宏吗?
【发布时间】:2014-01-22 18:50:18
【问题描述】:

我记得我在某处读到它不是宏,而是内置于核心语言中。类似的东西,我不确定,因为我已经不记得从哪里读到它了。 struct 是 Racket 中的宏吗?如果不是,为什么要内置在核心语言中?

【问题讨论】:

标签: racket


【解决方案1】:

一个宏; 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 函数来定位源代码(如果有的话)。

【讨论】:

  • 感谢您的回答。顺便问一下,这个Open Defining File在DrRacket的什么位置?
  • 在定义窗口中,右键单击源代码中的单词 struct。该选项应出现在上下文菜单中。如果 Racket 无法正确解析源代码,它有时会不起作用,因此请在语法正确的 s-expr 上使用它。
  • 请注意,结构扩展为define-struct/derived。新问题:define-struct/derived 是宏还是原语?
  • @soegaard:这是我想问的实际问题。只有在收到@uselpa 的完美答案后,我才意识到我问错了问题。所以正确的问题应该是制作 struct 类型的方法是否使用宏来实现。我发现答案是否定的。我从struct 一路追踪。你已经到达define-struct/derived,这也是一个定义在define-struct.rkt文件中的宏。
  • @soegaard:查看它的定义,您会发现一个名为make-struct-type 的过程,它在struct.c 中定义。我猜这意味着它是核心语言中的原始语言。
【解决方案2】:

我之前回答的时候好像误解了这个问题。所以这里是对这个问题的答案:

结构是内置的和原始的;它们是实施的基础。事实上,大约在 2007 年,Matthew Flatt 评论说,在 PLT Scheme(当时已知的 Racket)中,从某种意义上说,一切都是结构:

> 2007 年 5 月 31 日星期四 16:45:25 -0700,YC 写道:
> 出于好奇 - PLT 方案实际上是否使用 struct 作为基础
> 复合类型,即在结构之上实现闭包/等。

在我看来,一切都是结构,但有些东西使用 特殊情况表示,因为它们足够重要。 (这 极端情况是一个固定数字)。

但同样有效的答案是:不,并非所有复合类型都使用 与结构构造函数中的值相同的表示。

-- Source.

Start of the thread.

【讨论】:

  • 你认为 Flatt 持有这种观点是因为struct foo 创建了类型检查函数foo?,而将integer?boolean? 等视为根本上没有什么明显的优势不同种类的功能?
  • 好吧,马修花了几十年的时间思考概念和实施,所以我犹豫要不要把话放在他嘴里。如果你在邮件列表上问会更好。 :) 话虽如此:Racket 结构提供聚合、封装、继承和应用。从概念上讲?一切你需要的。现实吗?也许不吧。因为空间和/或因为速度。
【解决方案3】:

除了usepla的精彩回答,我想补充一下:

  1. 在 Racket 文档中,“蓝色框”的右上角有一个短语,例如 proceduresyntax。对于struct,它表示syntax

  2. 如果您考虑 struct 的作用,除其他外,它定义了从结构名称派生的命名函数。所以(struct foo (a b)) 将定义一个foo? 谓词和访问器foo-afoo-b。一个普通的函数不能像这样定义新的命名事物,所以它必须是一个宏。

【讨论】:

  • 我认为 OP 的问题不是宏 vs 过程,而是宏 vs 内置。
  • 啊我明白了。所以我刚刚发布了另一个答案。 :)
【解决方案4】:

通读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) 在实际版本中,大部分代码都处理可用于结构定义的属性。真实版本还需要处理任意数量的变量和替代形式、默认值等...

【讨论】:

    猜你喜欢
    • 2012-07-04
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 2017-01-28
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多