[racket] structure question

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Wed Dec 8 16:13:08 EST 2010



Here is a version with 'type' annotations that should be easier to read and learn from. 

#lang racket

;; -----------------------------------------------------------------------------
;; library module 

;; syntax def
;; definition = ... | (struct/kw name (field ...) options ...)
;; meaning:           (struct name (field ...) options ...) 
;;                     plus keyword-based constructor: name/kw
;; WARNING: the introduction of name/kw is non-hygienic 
;; NEW: allow optional default expressions on field-s
;; WARNING: this new option will interfere with the #:auto field option

(define-syntax (struct/kw stx)
  (syntax-case stx ()
    [(_ name (field ...) . stuff)
     (let* (;; [Listof Syntax/Field]
            [field* (syntax->list #'(field ...))]
            ;; [Listof Syntax/Identfier]
            [fields (map (lambda (f)
                           (syntax-case f ()
                             [(name default) #'name]
                             [name f]))
                         field*)]
            ;; Syntax/Identifier -> Keyword 
            [symbol-as-keyword
             (lambda (name)
               (string->keyword (symbol->string (syntax-e name))))]
            ;; Parameter = [List Keyword Syntax/Identfier]
            ;;           U [List Keyword [List Syntax/Identifier Syntax]]
            ;; Syntax/Field -> Parameter 
            [field-to-kw-param
             (lambda (f)
               (syntax-case f ()
                 [[name default] 
                  `(,(symbol-as-keyword #'name) (,#'name ,#'default))]
                 [name 
                  `(,(symbol-as-keyword f) ,f)]))]
            ;; [Listof Parameter]
            [parameters 
             (foldr (lambda (f r) (append (field-to-kw-param f) r)) '[] field*)]
            ;; Syntax/Identfier 
            [name/kw 
             (datum->syntax stx 
                            (string->symbol 
                             (string-append
                              (symbol->string (syntax-e #'name)) "/kw")))])
       #`(begin
           (struct name #,fields . stuff)
           (define (#,name/kw #, at parameters)
             (name #, at fields))))]))




;; -----------------------------------------------------------------------------
;; usage example (could be separate module)
(define detail-default "?")
(struct/kw book (author title [details detail-default]) #:transparent)

(define book1 (book/kw #:title "The Client" #:author "John Grisham"))

(define book2 (book/kw #:title "The Client" #:author "John Grisham" #:details "?"))

(string=? (book-author book1) "John Grisham") 
(string=? (book-details book2) "?")




Posted on the users mailing list.