From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([209.51.188.92]:45819) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h7iho-0003th-Js for guix-patches@gnu.org; Sat, 23 Mar 2019 11:37:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h7iQI-0006Ty-FC for guix-patches@gnu.org; Sat, 23 Mar 2019 11:19:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:42127) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h7iQI-0006Tm-9I for guix-patches@gnu.org; Sat, 23 Mar 2019 11:19:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1h7iQI-0006Ha-2y for guix-patches@gnu.org; Sat, 23 Mar 2019 11:19:02 -0400 Subject: [bug#34948] [PATCH 1/3] records: Allow thunked fields to refer to 'this-record'. Resent-Message-ID: From: Ludovic =?UTF-8?Q?Court=C3=A8s?= References: <20190322172120.10974-1-ludo@gnu.org> <20190322172719.11199-1-ludo@gnu.org> <87y35660fw.fsf@elephly.net> Date: Sat, 23 Mar 2019 16:18:11 +0100 In-Reply-To: <87y35660fw.fsf@elephly.net> (Ricardo Wurmus's message of "Fri, 22 Mar 2019 22:53:07 +0100") Message-ID: <87imw9zkjw.fsf@gnu.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+kyle=kyleam.com@gnu.org Sender: "Guix-patches" To: Ricardo Wurmus Cc: 34948@debbugs.gnu.org Hi! Ricardo Wurmus skribis: > Ludovic Court=C3=A8s 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=E2=80=99s now a one-argument procedure. It doesn=E2=80=99t matt= er much though because users never see this procedure. > I=E2=80=99m having difficulties understanding how this works. Why does t= he > =E2=80=9Cthunked field=E2=80=9D now require an argument (=E2=80=9Cx=E2=80= =9D)? This argument is the record itself, then bound to =E2=80=98this-record=E2= =80=99 in the lexical scope of the field. > We use the syntax parameter =E2=80=9Cthis-record=E2=80=9D to introduce a = new binding > with this name in the context of the =E2=80=9Cvalue=E2=80=9D of the field= . The > parameter value is =E2=80=A6 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 =E2=80=98x=E2=80=99 is the identifier of a variable that exists at run= time. So we cannot write #,x because we=E2=80=99d be referring to a variable =E2=80=98x= =E2=80=99 that exists at macro-expansion time, and there=E2=80=99s no such variable here. The =E2=80=98syntax-case=E2=80=99 here is just so that =E2=80=98this-record= =E2=80=99 matches only when used as an identifier, like this: (foo this-record) =E2=80=A6 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=E2=80=99s slightly less precise. A macro expansion is worth a thousand words :-), so: --8<---------------cut here---------------start------------->8--- scheme@(guix records)> (define-record-type* foo make-foo foo? (bar foo-bar (default 42)) (baz foo-baz (thunked))) scheme@(guix records)> ,optimize (foo-baz x) $11 =3D (let ((x x)) ((if (eq? (struct-vtable x) ) (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 =3D (begin (if (eq? #{% abi-cookie}# 2292347072401235576) (if #f #f) (throw 'record-abi-mismatch-error 'abi-check "~a: record ABI mismatch; recompilation needed" (list ) '())) (let ((s (allocate-struct 2))) (struct-set! s 0 42) (struct-set! s 1 (lambda (x) (+ 77 (if (eq? (struct-vtable x) ) (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=E2=80=99.