[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Macro for replacing a placeholder in an expression

From: Maxime Devos
Subject: Re: Macro for replacing a placeholder in an expression
Date: Sat, 30 Jul 2022 22:44:43 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0

On 30-07-2022 17:42, Zelphir Kaltstahl wrote:


But now comes the problem:

Since I want to replace all occurrences of for example <?> and <?> does not need to be defined, I think I must use define-syntax, to avoid Guile trying to evaluate the arguments to a function call. OK, so a macro I write:

(define-syntax replace-placeholder
   (λ (stx)
     (syntax-case stx (<?>)
       [(_ replacement <?>)
        (syntax replacement)]
       [(_ replacement (car-elem . cdr-elem))
         ((unsyntax (replace-placeholder #'replacement #'car-elem)) .
          (unsyntax (replace-placeholder #'replacement #'cdr-elem))))]
       [(_ replacement other)
        (syntax other)])))


When I use this on a trivial expression, it works:

(replace-placeholder 3 <?>)
=> 3

When I try to use this for a pair as follows:

(replace-placeholder 3 (+ 1 <?>))
=> While compiling expression:
Wrong type to apply: #<syntax-transformer replace-placeholder>

It does not work. What happens here, I guess, is, that the macro gets expanded, then the syntax-transformer ends up in a place like (replace-placeholder …) and since it is not a function, it cannot be applied.

I think so to -- syntax isn't procedure.

But this is exactly what I want! I want Guile to do another macro call right there and replace in the sub-expression. How can I tell Guile to do that?

To use replace-placeholder as a procedure, you can simply turn it into a procedure, by replacing define-syntax with define. Now, because in the end you want syntax and not just a procedure, you also define a small wrapper using define-syntax.  I expect you will end up with something similar to the 'replace-placeholder + replace-result-placeholder' example I sent previously.  If you really want to, there is is also the 'macro-transformer' procedure. If you don't like a separate helper procedure (maybe in an eval-when) defined outside the define-syntax, there are some tricks to avoid that if you are interested?

I think that only now I am understanding properly what you wrote: "Also, such a construct does not nest well, you can't put a replace-result-placeholder inside a replace-result-placeholder meaningfully, […]". Does this mean, that recursive application of a macro inside a macro is impossible? To expand to subforms being the same macro again and this way transform a whole tree of s-expressions?

No, this is not what I meant. What I meant is that things like the following won't work well:

(define (plus-one x)
  (replace-result-placeholder x
    (+ <?> (replace-result-placeholder 1 <?>))))

-- if I read this, I would expect it to be equivalent to (lambda (x) (+ x 1)), but IIUC, both the innermost and outermost <?> will be replaced by x so you end up with (lambda (x) (+ x x)) instead (unverified).

"All I want to do" is to replace some placeholder (in this case <?>) in an arbitrary form. No matter how that form looks or how deeply it is nested, if there are <?> inside of it, I want to replace them. Is this impossible?

Yes, see e.g. the replace-placeholder+replace-result-placeholder I sent, subject to the limitations of messy nesting semantics. However ...

Ultimately this is a sub-problem of a bigger thing I want to do. Part of the contracts thingy. I want to make it so, that the following is valid and works:

(define-with-contract account-withdraw
   (require (<= amount account-balance)
            (>= amount 0))
   (ensure (>= <?> 0)
   (λ (amount account-balance)
     (- account-balance amount)))

In SRFI 197 someone seems to have done that: The underscore _ can be anywhere and the result of previous chain steps will be put there.

Perhaps I have to check how that is implemented

..., while I'm not familiar with SRFI 197, I would doubt that that SRFI does this in __all__ contexts -- I would expect it to keep (quote _) intact (unverified, maybe SRFI actually _does_ change that?).

If you want to _not_ change (quote _), try defining <?> as a syntax parameter (see (guile)Syntax Parameters) and using syntax-parameterize -- if so, you can implement your thing with only syntax-rules and not syntax-case (maybe the nesting limitation would be solved too, but I don't actually know that for a fact).


Attachment: OpenPGP_0x49E3EE22191725EE.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]