[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))
(quasisyntax
((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)
arbitrarily-complex-expression-here-where-placeholder-will-be-replaced-with-function-result-identifier)
(λ (amount account-balance)
(- account-balance amount)))
~~~~
In SRFI 197 someone seems to have done that:
https://srfi.schemers.org/srfi-197/srfi-197.html 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).
Greetings,
Maxime.
OpenPGP_0x49E3EE22191725EE.asc
Description: OpenPGP public key
OpenPGP_signature
Description: OpenPGP digital signature
Re: Macro for replacing a placeholder in an expression, Maxime Devos, 2022/07/27