From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id mDjsMxaT3mLSJwEAbAwnHQ (envelope-from ) for ; Mon, 25 Jul 2022 14:56:54 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id 0HOwMxaT3mLDQAAAauVa8A (envelope-from ) for ; Mon, 25 Jul 2022 14:56:54 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 78FB014849 for ; Mon, 25 Jul 2022 14:56:54 +0200 (CEST) Received: from localhost ([::1]:49212 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oFxdl-0007DG-ND for larch@yhetil.org; Mon, 25 Jul 2022 08:56:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51752) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oFxJP-0000lD-KW for help-guix@gnu.org; Mon, 25 Jul 2022 08:35:54 -0400 Received: from mailrelay.tugraz.at ([129.27.2.202]:12171) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oFxJL-0008V3-89 for help-guix@gnu.org; Mon, 25 Jul 2022 08:35:51 -0400 Received: from lprikler-laptop.ist.intra (gw.ist.tugraz.at [129.27.202.101]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4Lrzz550yPz3wcQ; Mon, 25 Jul 2022 14:35:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1658752529; bh=1eRYbbEzLNp21AU3eJue90JWiw4PcOrKnQU3tlRD6aw=; h=Subject:From:To:Date:In-Reply-To:References; b=l+hkERbuNRILXaQ/atqyTg2waoz4KgcCJUaCYs9i9WgaSdid5W2epYCUYC2oOkAO/ rPUYlVeehYwMLxJYuhnQcjf4gZTlqU3QUTGn2uy+ZaWyFCWSeQK432RGEhaTWvRCTS tE+7fP3YkbMjhoyBjue3eFaw+Dx65GBf7605mYjg= Message-ID: <85aa861298d2f7232f147c72ca65b706c08c5ce9.camel@ist.tugraz.at> Subject: Re: boiler plate generation with hygenic macros in guile From: Liliana Marie Prikler To: Blake Shaw , help-guix@gnu.org Date: Mon, 25 Jul 2022 14:35:28 +0200 In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.42.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TUG-Backscatter-control: waObeELIUl4ypBWmcn/8wQ X-Scanned-By: MIMEDefang 2.74 on 129.27.10.116 Received-SPF: none client-ip=129.27.2.202; envelope-from=liliana.prikler@ist.tugraz.at; helo=mailrelay.tugraz.at X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: help-guix@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-guix-bounces+larch=yhetil.org@gnu.org Sender: "Help-Guix" X-Migadu-Flow: FLOW_IN X-Migadu-To: larch@yhetil.org X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1658753814; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=1eRYbbEzLNp21AU3eJue90JWiw4PcOrKnQU3tlRD6aw=; b=CTN4cH61k8GXQ66TNWFotfBppS8afbONuch5WDRqAdRQ5bvi7q/EOWRTSqRwkgcDR0U7TW /Gotau8ZBuzr71Xz1Q9w0gQemY/Rn9rUTtpyFuz9yyH+z1NeYVo1VTnYoNs8qZs26pnibP sJT2YY7yfnO1+x5z45dmxdueWHxHvyTTpSK5rmWAk2x4rudmj3lKrlq0l0QGywVflqR0Lb O8HIEFuP3J+r8ReYQNX846tyiaa8hPHiJwBEDRjV32XJofYhb5hRSZD5UrXX8UiyjlCJaW 0/W9s3aOaG3mNnrHdgjbCW2pRXMeJ66ygu8XMevKUIK5TIQ42PVJUb9UjDZLjA== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1658753814; a=rsa-sha256; cv=none; b=a6hD+aC9OT5zF62mL/TY6D8z7vSGuIgLalsTt7Pwa+BUgTbiGyHPa5COx0//M2DtjSpXeK goYvr1hVuSUx2Y3S1O1rVmYnkiz28QT7V/40HbmAxfDZnG4u2PzUSfGgaJtJV9cEFl9AOC AyBW1SKXPqPEAKmRX02S0UInTrfTbd6Wvc1IoZKbfHMMzDrZmPApFMHcYI1nyFQEAJHuB+ bCSi8F4LlHVV1aKw1zNErw2QjTtITw/0mqBWv7du4LpUUouxKT0jiDd29GnbEGMHNIv/nO HCEJUAhjvflRD07uzGPYQKVGUVyXmolz2wmAFGNuyBjZ7RmOpRcDu/L9a52NPA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=tugraz.at header.s=mailrelay header.b=l+hkERbu; dmarc=pass (policy=none) header.from=tugraz.at; spf=pass (aspmx1.migadu.com: domain of "help-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="help-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -7.63 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=tugraz.at header.s=mailrelay header.b=l+hkERbu; dmarc=pass (policy=none) header.from=tugraz.at; spf=pass (aspmx1.migadu.com: domain of "help-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="help-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: 78FB014849 X-Spam-Score: -7.63 X-Migadu-Scanner: scn0.migadu.com X-TUID: Wrrg+u+UOAPV Hi Blake, Am Mittwoch, dem 20.07.2022 um 23:57 +0000 schrieb Blake Shaw: > Ah! sorry, let me begin again: > > Right now I am working on a window manager extension system in Guile > and GOOPs, and I want to eliminate the boilerplate for generating class > slots, with a syntax-case macro like: > > #+begin_example scheme > (define-syntax slot-machine >     (λ (form) >       (syntax-case form () >     ((_ category quality value) >        #'(let* ((sym      (symbol-append category '- quality)) >         (set-sym! (symbol-append 'set- sym '!)) >         (get-sym  (symbol-append 'get- sym)) >         (acc-sym  (symbol-append 'acc- sym))) >         (if (or (symbol? value) (string? value) (number? value)) >         (quasiquote (,sym #:init-value value >                   #:setter       ,set-sym! >                   #:getter       ,get-sym >                   #:accessor   ,acc-sym)) >         (quasiquote (,sym #:init-form  value >                   #:setter       ,set-sym! >                   #:getter       ,get-sym >                   #:accessor   ,acc-sym)))))))) > #+end_example Now, first of all, I'd advise you to use (macroexpand '(expression)) whenever debugging your syntax-rules or syntax-cases. In this example, > (macroexpand (slot-machine 'inner 'quality #t)) yields > # (const #:setter) (toplevel set-inner-quality!) (const #:getter) > (toplevel get-inner-quality) (const #:accessor) (toplevel acc-inner- > quality))> but with an additional quote that's > append) (const inner) (const -) (const quality))) (let (set-sym!) (set- > sym!-1dff1b83541ce327-b6) ((call (toplevel symbol-append) (const set-) > (lexical sym sym-1dff1b83541ce327-b4) (const !))) (let (get-sym) (get- > sym-1dff1b83541ce327-b8) ((call (toplevel symbol-append) (const get-) > (lexical sym sym-1dff1b83541ce327-b4))) (let (acc-sym) (acc-sym- > 1dff1b83541ce327-ba) ((call (toplevel symbol-append) (const acc-) > (lexical sym sym-1dff1b83541ce327-b4))) (if (let (t) (t- > 1dff1b83541ce327-bd) ((call (toplevel symbol?) (const #t))) (if > (lexical t t-1dff1b83541ce327-bd) (lexical t t-1dff1b83541ce327-bd) > (let (t) (t-1dff1b83541ce327-c0) ((call (toplevel string?) (const #t))) > (if (lexical t t-1dff1b83541ce327-c0) (lexical t t-1dff1b83541ce327-c0) > (call (toplevel number?) (const #t)))))) (call (@@ (guile) list) > (lexical sym sym-1dff1b83541ce327-b4) (const #:init-value) (const #t) > (const #:setter) (lexical set-sym! set-sym!-1dff1b83541ce327-b6) (const > #:getter) (lexical get-sym get-sym-1dff1b83541ce327-b8) (const > #:accessor) (lexical acc-sym acc-sym-1dff1b83541ce327-ba)) (call (@@ > (guile) list) (lexical sym sym-1dff1b83541ce327-b4) (const #:init-form) > (const #t) (const #:setter) (lexical set-sym! set-sym!- > 1dff1b83541ce327-b6) (const #:getter) (lexical get-sym get-sym- > 1dff1b83541ce327-b8) (const #:accessor) (lexical acc-sym acc-sym- > 1dff1b83541ce327-ba)))))))> Ouch. > With this I can call (slot-machine 'inner 'color "green") to produce > what looks like an acceptable slot definition: > => (inner-color #:init-value "#BF3D52" #:setter set-inner-color! > #:getter get-inner-color #:accessor acc-inner-color) Note that you're confusing symbols and syntax here. A common mistake for the novice macro expander, but in Scheme, symbols and syntax are distinct. > Indeed, if I define a class with this slot definition in place, it > works fine: > > #+begin_example scheme > > (define-class () >     (inner-color #:init-value "#BF3D52" #:setter set-inner-color! > #:getter > get-inner-color #:accessor acc-inner-color)) > > (describe ) > => is a class. It's an instance of > Superclasses are: >     > Directs slots are: >     inner-color > (No direct subclass) > Class Precedence List is: >     >     >     > Class direct methods are: >     Method #< ( ) 7f7b27e10ac0> >          Generic: setter:acc-inner-color >     Specializers: >     Method #< () 7f7b27e10b00> >          Generic: acc-inner-color >     Specializers: >     Method #< ( ) 7f7b27e10b40> >          Generic: set-inner-color! >     Specializers: >     Method #< () 7f7b27e10b80> >          Generic: get-inner-color >     Specializers: > > #+end_example > > But if I try to use `slot-machine` inside a class definition i'm out > of luck: > > (define-class () >   (slot-machine 'inner 'color "green")) > => While compiling expression: > Syntax error: > socket:7257:0: source expression failed to match any pattern in form > (define-class-pre-definition ((quote inner) (quote color) "green")) Now if we were to try and debug this with our newly found trick, we'd quickly end up disappoined. macroexpand can not expand this form for the same reason as above: the source expression does not match any pattern in define-class. But what does this mean? See, if you write your code as you did above, define-class will look at the form (slot-machine 'inner 'quality #t) – in its unexpanded form! – decide, that it can't handle it, and raise the above error. Instead, you need a macro which expands to > (define-class () (inner-quality #:init-value #t #:setter > set-inner-quality! #:getter get-inner-quality #:accessor > acc-inner-quality))) which IOW means wrapping define-class in a macro. As a handy little guide, see the macroexpand blow without define-class actually defined. Note the extra quote around (), which you'll have to remove in your output. > (macroexpand '(define-class '() (inner-quality #:init-value > #t #:setter set-inner-quality! #:getter get-inner-quality #:accessor > acc-inner-quality))) > $1 = #) > (const ()) (call (toplevel inner-quality) (const #:init-value) (const > #t) (const #:setter) (toplevel set-inner-quality!) (const #:getter) > (toplevel get-inner-quality) (const #:accessor) (toplevel > acc-inner-quality)))> > I have tried to remedy this in a number of ways, using datum->syntax, > quasisyntax/unsyntax, make-variable and by defining a new syntax-case > macro to define classes, all without luck. So we now arrive at the conclusion that only a syntax-rules/syntax-case wrapper around define-class can remedy this, but you're still tasked with the actual implementation. Note, that the symbol-append of 'inner '- 'quality actually gets you nothing and only restricts you. I'd also advise you to keep compatibility with define-class as much as possible, that will significantly lessen your work. Then you "only" need to add your own special expansion rules with extra literals (literals go between the first pairs of parentheses in syntax-rules/syntax-case). Cheers