From unknown Fri Jun 20 05:36:42 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#62510 <62510@debbugs.gnu.org> To: bug#62510 <62510@debbugs.gnu.org> Subject: Status: [PATCH] docs: Add example clarifying how syntax-case renames symbols Reply-To: bug#62510 <62510@debbugs.gnu.org> Date: Fri, 20 Jun 2025 12:36:42 +0000 retitle 62510 [PATCH] docs: Add example clarifying how syntax-case renames = symbols reassign 62510 guile submitter 62510 antlers severity 62510 normal tag 62510 patch thanks From debbugs-submit-bounces@debbugs.gnu.org Tue Mar 28 21:37:01 2023 Received: (at submit) by debbugs.gnu.org; 29 Mar 2023 01:37:01 +0000 Received: from localhost ([127.0.0.1]:50987 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1phKkG-0002nj-Fl for submit@debbugs.gnu.org; Tue, 28 Mar 2023 21:37:01 -0400 Received: from lists.gnu.org ([209.51.188.17]:56126) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1phJbN-0006sU-Pp for submit@debbugs.gnu.org; Tue, 28 Mar 2023 20:23:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1phJbN-0003GQ-Gz for bug-guile@gnu.org; Tue, 28 Mar 2023 20:23:45 -0400 Received: from wnew1-smtp.messagingengine.com ([64.147.123.26]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1phJbL-0006fV-CG for bug-guile@gnu.org; Tue, 28 Mar 2023 20:23:45 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.west.internal (Postfix) with ESMTP id D2AFA2B068B5 for ; Tue, 28 Mar 2023 20:23:39 -0400 (EDT) Received: from imap44 ([10.202.2.94]) by compute4.internal (MEProxy); Tue, 28 Mar 2023 20:23:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=illucid.net; h= cc:content-type:content-type:date:date:from:from:in-reply-to :message-id:mime-version:reply-to:sender:subject:subject:to:to; s=fm1; t=1680049419; x=1680053019; bh=Bu5lG1oHb4Lak8YsJAzrjO769 YA9pi025JwmCMjLph4=; b=rnmplbOXW+CuXRVEcGYlMZkl4aZvaEYIDYoeZokVu gviYkaY7HebeDyGpyyY0Z4WYmfU9hDX15pHQbBEU3jKoxTW8EIOG9v3IwihLAPBj jmfrNAVvvixH4tqTr+1kgaqCIn4P3RbLDVeglH0OXmSYkcHCKghekYLzxzI3iFN9 A4u8bnFSveHvbd7sk/m4Bci1Dfw4Dr+dgu1idxiLsovqKwhWIGZw28xN/dLlcTrD mwqSrb0PAPYfD1EIwsv1Xl/svOBzgpwLh3LJATnsHq8QKHE3BNo08CG1mIEOOL7m Aw8wpnCr/JJhQJwlMaUaA2EFDJn2PrJoC07FzzSgHSZvg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:message-id :mime-version:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1680049419; x=1680053019; bh=Bu5lG1oHb4Lak8YsJAzrjO769YA9pi025Jw mCMjLph4=; b=GLh5quxyuB6SX2Q3/T7d8fwhPuSU5hmIbEWtYuKj0qpLfDS7+4Y zXa1zwfMQhT4ARbHTRp7gZysrItyM09L2ofg9F7SJT/tw/JKXGListmKhWAGd+T1 z1VTMgZGuBARpQcJ6e25q10NBJt8yQOoveBS82nRdcpFFXIKb4OWYZbmxvP0nWR2 69nJsdzkGH9ZT6JKIXB/Mf121Bkb4UmFLpejZQsDRv83Xa29/ZN6cJp1n24l85CM MUWqkaKd7VXFXXnpeFUpw5L58shlvStfceJ8swLigecMHPyI91YP3NdD6bh1mc9j xWEQ8Cpmk9mHYkL9c36tmWmdTqKBqrS1Zog== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrvdehhedgfeegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefofgggpffkfffhvffutgesthdtre dtreertdenucfhrhhomheprghnthhlvghrshcuoegrnhhtlhgvrhhssehilhhluhgtihgu rdhnvghtqeenucggtffrrghtthgvrhhnpefgvddtvefhjeevkeeiteefjefggeeuveeuhf dvffektdeuffdtieefvddtffehgeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpegrnhhtlhgvrhhssehilhhluhgtihgurdhnvght X-ME-Proxy: Feedback-ID: i7f11465a:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 0DFE136A007B; Tue, 28 Mar 2023 20:23:38 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.9.0-alpha0-237-g62623e8e3f-fm-20230327.001-g62623e8e Mime-Version: 1.0 Message-Id: <6f4f660c-dd7a-4055-84b3-7f96915df925@app.fastmail.com> Date: Wed, 29 Mar 2023 00:23:17 +0000 From: antlers To: bug-guile@gnu.org Subject: [PATCH] docs: Add example clarifying how syntax-case renames symbols Content-Type: text/plain Received-SPF: pass client-ip=64.147.123.26; envelope-from=antlers@illucid.net; helo=wnew1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: submit X-Mailman-Approved-At: Tue, 28 Mar 2023 21:36:59 -0400 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.4 (--) I encountered these renamed symbols in the wild, and it took quite a while for me to figure out what was going on. I'm glad to have learned a lot about syntax-case in the process, all the way through to Primer for the Mildly Insane, but I think it would spare future learners some trouble to have an example of this behavior just so that they know what's going on when they run into it. I've kinda awkwardly shoved the example into the most relevant place in the manual, but I'm not sure that I'm happy with how it all flows, as I am kinda taking a tangent for the sake of exposing these ideas. The segue back is especially rough as I didn't want to cut the existing example, so there are now code blocks two serving the same purpose. Oh and I'm new to this Thx! PS: Apologies if I've opened two bugs for this, I've switched mail providers and am not convinced that it went through on the first try about an hour ago. * doc/ref/api-macros.texi (Why syntax-case?): Document symbol renaming more clearly. --- doc/ref/api-macros.texi | 89 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/doc/ref/api-macros.texi b/doc/ref/api-macros.texi index a353719cb..5777eda7b 100644 --- a/doc/ref/api-macros.texi +++ b/doc/ref/api-macros.texi @@ -630,6 +630,8 @@ To begin with, we should mention a solution that doesn't work: ((_ test then else) #'(let ((it test)) (if it then else)))))) +(aif 't it #f) +;; => Unbound variable: it @end example The reason that this doesn't work is that, by default, the expander will @@ -682,6 +684,8 @@ Here's another solution that doesn't work: (let ((it (datum->syntax x 'it))) #'(let ((it test)) (if it then else))))))) +(aif 't it #f) +;; => Unbound variable: it @end example The reason that this one doesn't work is that there are really two @@ -689,9 +693,85 @@ environments at work here -- the environment of pattern variables, as bound by @code{syntax-case}, and the environment of lexical variables, as bound by normal Scheme. The outer let form establishes a binding in the environment of lexical variables, but the inner let form is inside a -syntax form, where only pattern variables will be substituted. Here we -need to introduce a piece of the lexical environment into the pattern -variable environment, and we can do so using @code{syntax-case} itself: +syntax form, where only pattern variables will be substituted. + +We can observe this effect with a similar macro that calls @code{(define +it ...)} by examining the resulting binding, using @code{it-1} and +@code{it-2} to distinguish the pattern variable from the syntax that we +intend to bind it to. + +@example +(define-syntax set-it-to-test + (lambda (x) + (syntax-case x () + ((_) + (let ((it-1 (datum->syntax x 'it-2))) + #'(define it-1 'test)))))) +(set-it-to-test) + +;; This hasn't worked: +(module-bound? (current-module) 'it-2) +;; => #f + +;; And hasn't bound it-1: +(module-bound? (current-module) 'it-1) +;; => #f + +;; But if we search for bindings that resolves to 'test, +;; we see something strange: +(module-map (lambda (sym val) + (when (eq? (variable-ref val) 'test) + (display (cons sym val)))) + (current-module)) +@print{} (it-1-ee83545680dc7ed . #) +@end example + +We can now see that the pattern symbol @code{it-1} has not been substituted to +@code{it-2} by the lexical binding, because the resulting variable binding +still carries the prefix @code{it-1}. + +However @code{it-1} has not been bound either! This is because it has been +renamed by the implementation of @code{syntax-case}, producing the gensym +@code{it-1-ee83545680dc7ed}. This is done to preserve referential transparency, +distinguishing our use of symbols like @code{if}, @code{define}, and @code{it} +in the @code{syntax} forms of the transformer's definition from their use in the +context of the form under expansion. + +This is the same mechanism which would rename the let-bound @code{it} in our +first example to prevent the @var{then} and @var{else} expressions from +accessing its binding. These internally renamed symbols aren't usually visible +in eg. macroexpansions or @code{display}'d symbols, but can sometimes be +observed doing their behind-the-scenes work within the top-level bindings of a +module. + +What we need to do is introduce the new syntax created by @code{datum->syntax} +into the pattern variable environment, which we can do with @code{syntax-case} +itself. + +@example +(define-syntax set-it-to-test + (lambda (x) + (syntax-case x () + ((_) + (syntax-case (datum->syntax x 'it-2) () + (it-1 + #'(define it-1 'test))))))) +(set-it-to-test) +it-2 +=> test +@end example + +Note that by providing the template-id @code{x} we explicitly specify +@emph{which} binding of @code{it-2} the new @code{syntax} inside our pattern +variable @code{it-1} refers to, namely the binding within the context of the +form being manipulated by the transformer, and we clarify to Guile that no +distinction should be created between these two uses of @code{it-2}. If we +provide a template-id from another (or no) context, the implementation might +still rename our @emph{new} syntax to something like +@code{it-2-ee83545680dc7ed} to prevent what might appear to be unintended +variable capture. + +Returning to our previous, pragmatic example: @example ;; works, but is obtuse @@ -710,8 +790,7 @@ variable environment, and we can do so using @code{syntax-case} itself: @print{} 500 @end example -However there are easier ways to write this. @code{with-syntax} is often -convenient: +There are easier ways to write this. @code{with-syntax} is often convenient: @deffn {Syntax} with-syntax ((pat val) @dots{}) exp @dots{} Bind patterns @var{pat} from their corresponding values @var{val}, within the -- 2.39.2