unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Zelphir Kaltstahl <zelphirkaltstahl@posteo.de>
To: Guile User <guile-user@gnu.org>
Subject: Macro for replacing a placeholder in an expression
Date: Wed, 27 Jul 2022 23:57:43 +0000	[thread overview]
Message-ID: <80083c86-19b0-7537-be70-f763bd5b390f@posteo.de> (raw)

Hello Guile Users,

I am trying to write a macro, which replaces all placeholders (in this case <?>) 
with an identifier in an arbitrarily structured expression (arbitrary nesting of 
expressions). I have the following code now:

~~~~
(define-syntax replace-result-placeholder
   (syntax-rules (<?> replace-result-placeholder)
     "Iterate through the parts of an expression, search for the
placeholder and replace the placeholder with the
result-identifier."
     ;; Transform trivial cases, base cases.
     [(_ result-identifier <?>)
      result-identifier]
     [(_ result-identifier (<?>))
      (result-identifier)]

     [(_ result-identifier (op))
      (op)]

     ;; If there already is such a list of transformed args
     ;; and there are still arguments not transformed.
     [(_ res-id-outer
         (op arg
             args* ...
             (list
              ;; Must match a compound expression here, to
              ;; avoid matching of other lists, like lists of
              ;; arguments in a lambda expression or
              ;; similar. Here we must only match a list of
              ;; arguments, which are yet to be transformed.
              (replace-result-placeholder res-id-inner arg-to-transform)
              other-args* ...)))
      (replace-result-placeholder
       res-id-outer
       (op args* ...
           (list (replace-result-placeholder res-id-outer arg-to-transform)
                 other-args* ...
                 (replace-result-placeholder res-id-inner arg))))]

     ;; If there already is such a list of transformed args
     ;; and there are no arguments not yet transformed.
     [(_ res-id-outer
         (op (list
              (replace-result-placeholder res-id-inner arg-to-transform)
              other-args* ...)))
      ((replace-result-placeholder res-id-outer op)
       (replace-result-placeholder res-id-inner arg-to-transform)
       other-args* ...)]

     ;; Create list of transformed args, if it does not yet
     ;; exist.
     [(_ result-identifier (op arg args* ...))
      (replace-result-placeholder
       result-identifier
       (op args* ...
           (list
            (replace-result-placeholder result-identifier arg))))]

     ;; Must place this trivial case last, to avoid
     ;; accidental matching of compound expressions.
     [(_ result-identifier op)
      op]

     ;; Catch all.
     [(_ other* ...)
      (syntax-error "unrecognized form in macro call:"
                    (quote
                     (replace-result-placeholder other* ...)))]
     ))
~~~~

This already seems to work mostly:

~~~~
scheme@(guile-user)> (define res 3)
scheme@(guile-user)> (replace-result-placeholder res <?>)
$18 = 3
scheme@(guile-user)> (replace-result-placeholder res (+ 1 <?>))
$19 = 4
scheme@(guile-user)> (replace-result-placeholder res (+ 1 (- 5 <?>)))
$20 = 3
scheme@(guile-user)> (replace-result-placeholder res (+ 1 (* <?> 2) (- 5 <?>)))
$21 = 9
scheme@(guile-user)>
~~~~

I was already happy, because everything seemed to work. However, when it comes 
to replacing things inside lambda expressions, things seem to not work correctly:

~~~~
scheme@(guile-user)> (replace-result-placeholder res (lambda (a) (+ a <?>)))
While compiling expression:
Syntax error:
unknown file:965:0: lambda: invalid argument list in subform ((a)) of (replace-result-placeholder res (a))
~~~~

I think (but not 100% sure), that the ((a)) comes from the case:

~~~~
...
[(_ result-identifier (op))
      (op)]
...
~~~~

(In this case it is not an "operation", but nevermind the name in that pattern.) 
I do not understand, why it outputs something which is wrapped twice in 
parentheses. I do not understand where that second pair of parentheses comes from.

I tried creating a simpler macro, for the specific case of a lambda expression, 
to maybe find a solution this way. But it has got the same problem. At least it 
now serves to reproduce the problem in a simpler example:

~~~~
scheme@(guile-user)> (define-syntax test
   (syntax-rules (lambda)
     [(_ (op args body* ...))
      ((test op) (test args) (test body* ...))]

     [(_ thing1 thing2 things* ...)
      ((test thing1) (test thing2 things* ...))]

     [(_ (thing))
      (thing)]

     [(_ thing)
      thing]))
scheme@(guile-user)> (test (lambda (a) (+ a 1)))
While compiling expression:
Syntax error:
unknown file:798:0: lambda: invalid argument list in subform ((a)) of (test (a))
~~~~

There seems to be something about a template like (one-thing) that I do not 
understand or something completely different is going on.

What am I doing wrong?

Best regards,
Zelphir

-- 
repositories: https://notabug.org/ZelphirKaltstahl




             reply	other threads:[~2022-07-27 23:57 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-27 23:57 Zelphir Kaltstahl [this message]
2022-07-28  0:55 ` Macro for replacing a placeholder in an expression Maxime Devos
2022-07-28 10:23   ` Zelphir Kaltstahl
2022-07-28 10:28     ` Maxime Devos
2022-07-30 15:42     ` Zelphir Kaltstahl
2022-07-30 20:44       ` Maxime Devos
2022-07-30 21:10         ` Maxime Devos
2022-07-30 21:13       ` Maxime Devos
2022-08-05  9:42         ` Linus Björnstam
2022-08-06 14:28           ` Zelphir Kaltstahl
2022-07-28  1:04 ` Maxime Devos
2022-07-28  8:39   ` Zelphir Kaltstahl
2022-07-28  9:48     ` Maxime Devos
2022-07-28 11:26       ` Zelphir Kaltstahl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=80083c86-19b0-7537-be70-f763bd5b390f@posteo.de \
    --to=zelphirkaltstahl@posteo.de \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).