day
day

Reputation: 2352

Is struct a macro in Racket?

I remember I read somewhere it is not a macro and is built into the core language. Something like that, I am not sure, because I can no longer remember from where I read it. So is struct a macro in Racket or not? If not, why is it built into the core language?

Upvotes: 2

Views: 596

Answers (4)

QuesterZen
QuesterZen

Reputation: 131

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...

Upvotes: 0

Greg Hendershott
Greg Hendershott

Reputation: 16250

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.

Upvotes: 3

Greg Hendershott
Greg Hendershott

Reputation: 16250

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.

Upvotes: 0

uselpa
uselpa

Reputation: 18917

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).

Upvotes: 3

Related Questions