define-record-type*: Add the `inherit' syntactic constructor keyword.
* guix/utils.scm (define-record-type*)[make-syntactic-constructor]: New `type' parameter. Add the `inherit' keyword and corresponding support code. * tests/utils.scm ("define-record-type* & inherit", "define-record-type* & inherit & letrec* behavior"): New tests.
This commit is contained in:
parent
c79dae6076
commit
dcd60f4398
|
@ -477,17 +477,41 @@ starting from the right of S."
|
||||||
"Define the given record type such that an additional \"syntactic
|
"Define the given record type such that an additional \"syntactic
|
||||||
constructor\" is defined, which allows instances to be constructed with named
|
constructor\" is defined, which allows instances to be constructed with named
|
||||||
field initializers, à la SRFI-35, as well as default values."
|
field initializers, à la SRFI-35, as well as default values."
|
||||||
(define (make-syntactic-constructor name ctor fields defaults)
|
(define (make-syntactic-constructor type name ctor fields defaults)
|
||||||
"Make the syntactic constructor NAME that calls CTOR, and expects all
|
"Make the syntactic constructor NAME for TYPE, that calls CTOR, and
|
||||||
of FIELDS to be initialized. DEFAULTS is the list of FIELD/DEFAULT-VALUE
|
expects all of FIELDS to be initialized. DEFAULTS is the list of
|
||||||
tuples."
|
FIELD/DEFAULT-VALUE tuples."
|
||||||
(with-syntax ((name name)
|
(with-syntax ((type type)
|
||||||
|
(name name)
|
||||||
(ctor ctor)
|
(ctor ctor)
|
||||||
(expected fields)
|
(expected fields)
|
||||||
(defaults defaults))
|
(defaults defaults))
|
||||||
#'(define-syntax name
|
#`(define-syntax name
|
||||||
(lambda (s)
|
(lambda (s)
|
||||||
(syntax-case s expected
|
(define (record-inheritance orig-record field+value)
|
||||||
|
;; Produce code that returns a record identical to
|
||||||
|
;; ORIG-RECORD, except that values for the FIELD+VALUE alist
|
||||||
|
;; prevail.
|
||||||
|
(define (field-inherited-value f)
|
||||||
|
(and=> (find (lambda (x)
|
||||||
|
(eq? f (car (syntax->datum x))))
|
||||||
|
field+value)
|
||||||
|
car))
|
||||||
|
|
||||||
|
#`(make-struct type 0
|
||||||
|
#,@(map (lambda (field index)
|
||||||
|
(or (field-inherited-value field)
|
||||||
|
#`(struct-ref #,orig-record
|
||||||
|
#,index)))
|
||||||
|
'expected
|
||||||
|
(iota (length 'expected)))))
|
||||||
|
|
||||||
|
|
||||||
|
(syntax-case s (inherit #,@fields)
|
||||||
|
((_ (inherit orig-record) (field value) (... ...))
|
||||||
|
#`(letrec* ((field value) (... ...))
|
||||||
|
#,(record-inheritance #'orig-record
|
||||||
|
#'((field value) (... ...)))))
|
||||||
((_ (field value) (... ...))
|
((_ (field value) (... ...))
|
||||||
(let ((fields (map syntax->datum #'(field (... ...))))
|
(let ((fields (map syntax->datum #'(field (... ...))))
|
||||||
(dflt (map (match-lambda
|
(dflt (map (match-lambda
|
||||||
|
@ -495,12 +519,12 @@ tuples."
|
||||||
(list (syntax->datum f) v)))
|
(list (syntax->datum f) v)))
|
||||||
#'defaults)))
|
#'defaults)))
|
||||||
|
|
||||||
(define (field-value f)
|
(define (field-value f)
|
||||||
(or (and=> (find (lambda (x)
|
(or (and=> (find (lambda (x)
|
||||||
(eq? f (car (syntax->datum x))))
|
(eq? f (car (syntax->datum x))))
|
||||||
#'((field value) (... ...)))
|
#'((field value) (... ...)))
|
||||||
car)
|
car)
|
||||||
(car (assoc-ref dflt (syntax->datum f)))))
|
(car (assoc-ref dflt (syntax->datum f)))))
|
||||||
|
|
||||||
(let-syntax ((error*
|
(let-syntax ((error*
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
|
@ -537,7 +561,7 @@ tuples."
|
||||||
(ctor field ...)
|
(ctor field ...)
|
||||||
pred
|
pred
|
||||||
(field get) ...)
|
(field get) ...)
|
||||||
#,(make-syntactic-constructor #'syntactic-ctor #'ctor
|
#,(make-syntactic-constructor #'type #'syntactic-ctor #'ctor
|
||||||
#'(field ...)
|
#'(field ...)
|
||||||
(filter-map field-default-value
|
(filter-map field-default-value
|
||||||
#'((field options ...)
|
#'((field options ...)
|
||||||
|
|
|
@ -132,6 +132,36 @@
|
||||||
(match (bar (z 21) (x (/ z 3)))
|
(match (bar (z 21) (x (/ z 3)))
|
||||||
(($ <bar> 7 42 21))))))
|
(($ <bar> 7 42 21))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & inherit"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (default (+ 40 2))))
|
||||||
|
(let* ((a (foo (bar 1)))
|
||||||
|
(b (foo (inherit a) (baz 2)))
|
||||||
|
(c (foo (inherit b) (bar -2)))
|
||||||
|
(d (foo (inherit c)))
|
||||||
|
(e (foo (inherit (foo (bar 42))) (baz 77))))
|
||||||
|
(and (match a (($ <foo> 1 42) #t))
|
||||||
|
(match b (($ <foo> 1 2) #t))
|
||||||
|
(match c (($ <foo> -2 2) #t))
|
||||||
|
(equal? c d)
|
||||||
|
(match e (($ <foo> 42 77) #t))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & inherit & letrec* behavior"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (default (+ 40 2))))
|
||||||
|
(let* ((a (foo (bar 77)))
|
||||||
|
(b (foo (inherit a) (bar 1) (baz (+ bar 1))))
|
||||||
|
(c (foo (inherit b) (baz 2) (bar (- baz 1)))))
|
||||||
|
(and (match a (($ <foo> 77 42) #t))
|
||||||
|
(match b (($ <foo> 1 2) #t))
|
||||||
|
(equal? b c)))))
|
||||||
|
|
||||||
(test-end)
|
(test-end)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue