From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id IoaHIsj44mI45wAAbAwnHQ (envelope-from ) for ; Thu, 28 Jul 2022 22:59:52 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id WCtbIcj44mJxYAEAauVa8A (envelope-from ) for ; Thu, 28 Jul 2022 22:59:52 +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 E17557DD0 for ; Thu, 28 Jul 2022 22:59:51 +0200 (CEST) Received: from localhost ([::1]:56668 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oHAbm-0005zE-32 for larch@yhetil.org; Thu, 28 Jul 2022 16:59:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:34622) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oHAbZ-0005ut-U6 for help-guix@gnu.org; Thu, 28 Jul 2022 16:59:38 -0400 Received: from mail-ed1-x530.google.com ([2a00:1450:4864:20::530]:43624) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1oHAbX-0001zA-9Z for help-guix@gnu.org; Thu, 28 Jul 2022 16:59:37 -0400 Received: by mail-ed1-x530.google.com with SMTP id z18so3626470edb.10 for ; Thu, 28 Jul 2022 13:59:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sweatshoppe-org.20210112.gappssmtp.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=fgAl2mSFYAiva9CbOpQnpSjymktahNh1K61MDKeKE8c=; b=cP6WzZE1DsfqRcf9pCGd6Gy0qwkeECU7WWvxguQh010yTHr1Ilwu2pebkevuCpAZcC odU2hOH/NQYZS1QEnlsDpTX36KCYWpkV/tAInSUO89nXaKnuGxaOdoC+rqqGf2WJrUIf ht6sWlg4IAaBaHt/BmGGKN1rjZ90RRt7NmkcSUeMJqhdA3/JGA11Wnkgv9IrCpgCN+IR u5HlHXEKPjqLvdbCajIFcc9Ng6mmpRk8DaYrIzbR3yDyPvOxsOsV/b14t/ylxhlGmJPY KPXZMI3fc1NjnDrnlJ1sh4tTrJVJw6Ndq07z02h7X87zLHgSD1tweTrJ/4vFLdLDLVCp jRJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=fgAl2mSFYAiva9CbOpQnpSjymktahNh1K61MDKeKE8c=; b=3dBUK3OhsoWeDN/RkW7ksBzBBvX6SANKyB8MFuqIq3f5i3bPYZmp4a3r9Y9vBGtVFn e7aJeCl4XU9Phm+KyvFLdBX1rCLXHkhoksQ/mq+oTN/yEkY3VWmiEFsQphPf7HWI36Kf pDpC/x+cIgK79sZOE6UZR9NnXacxCX7gT8e9afFDlbdxjhvGPj1oyyZn1YPTtOXNkPkb JtkrdZG6WHAFUlA9qG3YlxCXpeOp6f7xjepWkOD1s/QOo65yA6KWHJgdtJ+/TvaV5b/4 at94DBi1SdelQDG8nimAEI1Jy5FVCEXUm+ftLwIIPtK3zwk0aBx9nrFivABdlr4a44ex WUHg== X-Gm-Message-State: AJIora9qH/ytJHRbVX9njaq0w4TeJBvmv9ynsR0vCDHQUwpbstx/yDxm OQO8vykcPPitU7GsJ1VAR7+ZpyDSHBBxBtabtn4iGw== X-Google-Smtp-Source: AGRyM1sdEH5QAFgdcEHQgQ6SNH1bTRWP+KYdOMXdRDDOy704/Dpx+vemoeLLizcwu6765/GPM1leVQFOQY+5k2zyjAA= X-Received: by 2002:aa7:cac4:0:b0:43b:ddac:aa79 with SMTP id l4-20020aa7cac4000000b0043bddacaa79mr753425edt.202.1659041973344; Thu, 28 Jul 2022 13:59:33 -0700 (PDT) MIME-Version: 1.0 References: <85aa861298d2f7232f147c72ca65b706c08c5ce9.camel@ist.tugraz.at> In-Reply-To: <85aa861298d2f7232f147c72ca65b706c08c5ce9.camel@ist.tugraz.at> From: Blake Shaw Date: Thu, 28 Jul 2022 20:59:22 +0000 Message-ID: Subject: Re: boiler plate generation with hygenic macros in guile To: Liliana Marie Prikler Cc: help-guix@gnu.org, Maxime Devos Received-SPF: none client-ip=2a00:1450:4864:20::530; envelope-from=blake@sweatshoppe.org; helo=mail-ed1-x530.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.29 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=1659041992; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc: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=TbYoxsMddUqUzwdIkZUHwNGjcUZJyhi127UukrIoeaM=; b=pS/Pv2qp16k49AjDMVNKAqrThIVjYk4xsNJ+QNLywrZ/Y4tBmyFv1l+eM5E5BGMnu0iLqo CKJoFFiX/vrJMDQ2Zk3wplqHr2MByY+8Ap8wwbyk7chPTNR9d3EsK2PKpAgnkG+R97+Gws Lb2vNpiWIZMMqZbc6581TEO/OEo/Ryk6monXnzyTi44tO5qmctFi43M6s3iUv0ud4IQZHI do2Mvpj+lWhDBe8bJCSuYRoYCdOhr7IgAGu4SrTLNug3cQ4oHPRbS0rW6vM8fHpG2YwDWq hcff/vLeKMRro66IVJwEmSFbTWckT7iD3HEJ4npNgwH9IPRC8k+bDXL3gM8wZA== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1659041992; a=rsa-sha256; cv=none; b=Cxg1C8H883JopuBT7FAwcLtrDP1o06PZVVjGUv7fKOoLzRLbNRDse0p4RBESFETkYaCMdl xLJmANyRyBjKecxvmTJQIPwVfvjivGsBZlcQ+DuK1O6AOThQPe485TUn03VPyRhRW+UTe4 /qkUEX0glAe3FRawUBHmbv9CftHCSm02gAcreEJ1SafwNf0FAaj2ji5ebj2UfLADnu+8QQ 92dMgdsZZNqpFUVOUpV+Vwut07Wzp6BQ6rzqppVYW9aCugaX+oDdsOZyai+AVKyYNRVavL 59+n0cmpGlkdqrl2QGdURM5N2CSiwnoiXeLKbbF+QZ4+nBnw907vRwD3/j3nJQ== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=sweatshoppe-org.20210112.gappssmtp.com header.s=20210112 header.b=cP6WzZE1; dmarc=none; 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: 0.97 Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=sweatshoppe-org.20210112.gappssmtp.com header.s=20210112 header.b=cP6WzZE1; dmarc=none; 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: E17557DD0 X-Spam-Score: 0.97 X-Migadu-Scanner: scn0.migadu.com X-TUID: spgXh3oJIwt5 Hi Maxime & Liliana, I just want to pop in and say thanks for your advice, its been helpful. I almost have the implementation down, but a few tricky bits I still havent got right... (what I'm attempting is a little more tricky than the example I gave here, which I shortened for the sake of transmissibility -- the goal is to be able to generate classes from dictionaries in an ad-hoc manner). Feel like I'm almost there, just a few bits to work out, but I won't be able to return to it for another week or so. As soon as I have it down I'll report back in detail in case it could help others. Happy hacking! b On Mon, Jul 25, 2022 at 12:35 PM Liliana Marie Prikler < liliana.prikler@ist.tugraz.at> wrote: > > 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 > > (=CE=BB (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 > 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: > > =3D> (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 ) > > =3D> 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")) > > =3D> 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) =E2=80=93 in its unexpanded fo= rm! =E2=80=93 > 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 =3D #) > > (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