(rnrs records syntactic)とsrfi-17の一般化されたset!
(rnrs records syntactic)とsrfi-17を組み合わせて使いたかったんだけど,どうも手動でsetterをset!しなければならないようだったので,マクロの勉強ついでにsetterをset!してくれるものを書いた.
最初は手続きで書いてdefine-record-typeの後に置くようなものを書こうとしていたんだけど,record-(accessor|mutator)が(少なくともracketだと)毎回新しい手続きを返すために,書く事ができなかった.
R6RSやsyntax-case関連についてあまりよくわかっていないので,おかしいところが多々あるかもしれない.
ろくにテストしていないのでちゃんと動くかどうかもわからない.
#!r6rs (library (kaki records) (export define-record-type-with-setter fields mutable immutable parent protocol sealed opaque nongenerative parent-rtd) (import (for (rnrs base) run expand) (rnrs records syntactic) (rename (srfi :17) (set! srfi-17:set!)) (for (rnrs syntax-case) expand) (for (rnrs lists) expand) (for (only (srfi :1) filter-map) expand) (for (only (kaki util) let1 if-not-let1) expand)) (define-syntax define-record-type-with-setter (lambda (x) (syntax-case x () ((k name-spec . clauses) (let1 record-name (let1 spec (syntax->datum #'name-spec) (symbol->string (if (symbol? spec) spec (car spec)))) (define (accessor-name name) (string->symbol (string-append record-name "-" (symbol->string name)))) (define (mutator-name name) (string->symbol (string-append record-name "-" (symbol->string name) "-set!"))) (define (maybe-accessor&mutator spec) (and (pair? spec) (eq? 'mutable (car spec)) (if (null? (cddr spec)) (let1 field-name (cadr spec) (list (accessor-name field-name) (mutator-name field-name))) (cddr spec)))) (if-not-let1 field-clause (find (lambda (clause) (eq? 'fields (car clause))) (syntax->datum #'clauses)) #'(define-record-type name-spec . clauses) (let1 field-specs (cdr field-clause) (with-syntax ((set-setter (map (lambda (p) #`(srfi-17:set! (setter #,(datum->syntax #'k (car p))) #,(datum->syntax #'k (cadr p)))) (filter-map maybe-accessor&mutator field-specs)))) #'(begin (define-record-type name-spec . clauses) . set-setter))))))))) )
let1とif-not-let1の(やっつけ)実装は
(define-syntax let1 (syntax-rules () ((_ var expr body ...) (let ((var expr)) body ...)))) (define-syntax if-not-let1 (syntax-rules () ((_ var expr then else) (let ((var expr)) (if var else then)))))