[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug#34948] [PATCH 1/3] records: Allow thunked fields to refer to 'this-
From: |
Ludovic Courtès |
Subject: |
[bug#34948] [PATCH 1/3] records: Allow thunked fields to refer to 'this-record'. |
Date: |
Sat, 23 Mar 2019 16:18:11 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) |
Hi!
Ricardo Wurmus <address@hidden> skribis:
> Ludovic Courtès <address@hidden> writes:
>
>> * guix/records.scm (this-record): New syntax parameter.
>> (make-syntactic-constructor)[wrap-field-value]: When F is thunked,
>> return a one-argument lambda instead of a thunk, and parameterize
>> THIS-RECORD.
>
> So the value of the thunked field is no longer strictly a thunk?
Indeed, it’s now a one-argument procedure. It doesn’t matter much
though because users never see this procedure.
> I’m having difficulties understanding how this works. Why does the
> “thunked field” now require an argument (“x”)?
This argument is the record itself, then bound to ‘this-record’ in the
lexical scope of the field.
> We use the syntax parameter “this-record” to introduce a new binding
> with this name in the context of the “value” of the field. The
> parameter value is … hard to make out. How does the syntax-case macro
> in the following syntax-parameterize expression evaluate to the record
> itself? Would #,x not be sufficient to refer to the argument of the
> field accessor?
>
>> (define (wrap-field-value f value)
>> (cond ((thunked-field? f)
>> - #`(lambda () #,value))
>> + #`(lambda (x)
>> + (syntax-parameterize ((this-record
>> + (lambda (s)
>> + (syntax-case s ()
>> + (id
>> + (identifier? #'id)
>> + #'x)))))
Here ‘x’ is the identifier of a variable that exists at run time. So we
cannot write #,x because we’d be referring to a variable ‘x’ that exists
at macro-expansion time, and there’s no such variable here.
The ‘syntax-case’ here is just so that ‘this-record’ matches only when
used as an identifier, like this:
(foo this-record)
… and does not match when used like this:
(this-record)
or like that:
(this-record x y z)
We could just as well make it (identifier-syntax #'x) though that’s
slightly less precise.
A macro expansion is worth a thousand words :-), so:
--8<---------------cut here---------------start------------->8---
scheme@(guix records)> (define-record-type* <foo> foo make-foo foo?
(bar foo-bar (default 42))
(baz foo-baz (thunked)))
scheme@(guix records)> ,optimize (foo-baz x)
$11 = (let ((x x))
((if (eq? (struct-vtable x) <foo>)
(struct-ref x 1)
(throw 'wrong-type-arg
'%foo-baz-real
"Wrong type argument: ~S"
(list x)
(list x)))
x))
scheme@(guix records)> ,optimize (foo (baz (+ 77 (foo-bar this-record))))
$12 = (begin
(if (eq? #{% <foo> abi-cookie}# 2292347072401235576)
(if #f #f)
(throw 'record-abi-mismatch-error
'abi-check
"~a: record ABI mismatch; recompilation needed"
(list <foo>)
'()))
(let ((s (allocate-struct <foo> 2)))
(struct-set! s 0 42)
(struct-set!
s
1
(lambda (x)
(+ 77
(if (eq? (struct-vtable x) <foo>)
(struct-ref x 0)
(throw 'wrong-type-arg
'foo-bar
"Wrong type argument: ~S"
(list x)
(list x))))))
s))
--8<---------------cut here---------------end--------------->8---
I hope this clarifies things!
Ludo’.