[racket] structure question
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) "?")