Is struct a macro in Racket?

浪子不回头ぞ 提交于 2019-12-01 09:30:44

A macro; struct.rkthas

(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)]))))

In Racket IDE, you can use the Open Defining File function to locate the source code (if available).

It looks like I misunderstood the question, when I answered before. So here's an answer to the question that was meant:

Structs are built-in and primitive; they underpin the implementation. In fact, circa 2007, Matthew Flatt commented that in PLT Scheme (as Racket was known then), in a sense everything is a struct:

> At Thu, 31 May 2007 16:45:25 -0700, YC wrote:
> Out of curiosity - does PLT scheme actually use struct as the fundamental
> compound type, i.e. implement closure/etc on top of struct.

The way I think about it, everything is a struct, but some things use a special-case representation because they're important enough. (The extreme case is a fixnum).

But an equally valid answer would be: no, not all compound types use the same representation as values from a struct constructor.

-- Source.

Start of the thread.

In addition to usepla's great answer, I wanted to add:

  1. In the Racket documentation, the "blue box" has a phrase in the top right corner such as procedure or syntax. For struct it says syntax.

  2. If you think about what struct does, among other things it defines named functions derived from the name of the struct. So (struct foo (a b)) will define a foo? predicate and accessors foo-a, foo-b. A plain function can't define new named things like this, so, it must be a macro.

Reading through the implementation code in define-struct.rkt, if you want to do the same thing manually, the following code is a much simplified version of what it is doing.

(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) We have to create the names we will define: but we need to use syntax objects to do so

2) We generate code that will define all of the functions associated with the new object in the global namespace

3) In the real version, most of the code deals with the properties that can be used a struct definition. The real version also needs to handle arbitrary numbers of variables and alternative forms, defaults etc...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!