Re: Macro for replacing a placeholder in an expression

2022-07-30 Thread Zelphir Kaltstahl

Hi Maxime!

On 7/28/22 12:23, Zelphir Kaltstahl wrote:

Hello Maxime!

On 7/28/22 02:55, Maxime Devos wrote:


These macros all sound more complicated than necessary -- on the first one, 
I've sent you a message with sneek:


;; By: Maxime Devos

;; This does not recurse into #(...).
;; Also, such a construct does not nest well, you can't put a 
replace-result-placeholder inside a replace-result-placeholder meaningfully,
;; so I'm wondering why you're doing this, maybe your goal can be 
accomplished more robustly with a different method.

(eval-when (expand load eval)
   (define (replace-placeholder new code) ; <--- recursively transforms code 
to replace '' by new

 (syntax-case code ()
   ( new)
   ((x . y)
    #`(#,(replace-placeholder new #'x) . #,(replace-placeholder new #'y)))
   (rest #'rest

(define-syntax replace-result-placeholder
   (lambda (s)
 (syntax-case s () ; : placeholder
   ((_ new code) (replace-placeholder #'new #'code)

(display (replace-result-placeholder
    quote
    ( bar))) ; -> bar

(I think thinking in terms of 'operations' and special-casing lambda etc 
would make things harder here)


As a bonus, this supports things like `((x . ) (z . w)) which aren't 
supported by the original macro as that macro assumed lists.


Greetings,
Maxime.

I'll need to look at this and learn about eval-when. I also did not think 
about vectors yet. Thank you!


Best regards,
Zelphir


I've now tried to use syntax-case, trying to adapt your example to what I need. 
However, it seems again I am stuck.


From the docs I read that syntax-case needs to be wrapped into a lambda, 
because it is just a way of working with syntax objects, pattern matching on 
them, but it does not make a syntax transformer. To make an actual syntax 
transformer, it needs to be wrapped with a lambda. So far I understand it. It is 
like a normal (match ...), but for syntax:


"All of these differences stem from the fact that syntax-case does not define a 
syntax transformer itself – instead, syntax-case expressions provide a way to 
destructure a syntax object, and to rebuild syntax objects as output." -- 
https://www.gnu.org/software/guile/manual/html_node/Syntax-Case.html


OK fine. But in the manual the syntax-case is used with define-syntax, not with 
define, like in your example. I guess that is the difference between using it as 
part of a macro and using it as a helper in a function:


"It is not strictly necessary for a syntax-case expression to return a syntax 
object, because syntax-case expressions can be used in helper functions, or 
otherwise used outside of syntax expansion itself. However a syntax transformer 
procedure must return a syntax object, so most uses of syntax-case do end up 
returning syntax objects." -- 
https://www.gnu.org/software/guile/manual/html_node/Syntax-Case.html


I struggled a bit to bring arguments of the wrapping lambda in correspondence 
with the patterns I supply to the pattern matching in syntax-case, but now I 
understand, the lambda always has only one argument, if used inside a 
define-syntax and that one argument is the whole call, while in your example you 
used syntax-case inside a regular function, so the arguments are whatever you 
want to define them to be. So that I understand now.


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)])))


(I am still a bit not used to all the # shortcuts for (syntax …), (quasisyntax 
…) and (unsyntax …), so I wrote them out as words for now.)


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: #


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. 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?


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 i

Re: Macro for replacing a placeholder in an expression

2022-07-30 Thread Maxime Devos


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: #


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

2022-07-30 Thread Maxime Devos


On 30-07-2022 22:44, Maxime Devos wrote:


"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 ... 
Oops, double negative etc.  Correction: No, this is not impossible, it's 
possible, see e.g. the [...]


OpenPGP_0x49E3EE22191725EE.asc
Description: OpenPGP public key


OpenPGP_signature
Description: OpenPGP digital signature


Re: Macro for replacing a placeholder in an expression

2022-07-30 Thread Maxime Devos


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


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?


You can have recursive macros, see e.g. the let^ macro at 
.


However, I do not see a way to implement recursivity the same way for 
your macro.


Greetings,
Maxime.



OpenPGP_0x49E3EE22191725EE.asc
Description: OpenPGP public key


OpenPGP_signature
Description: OpenPGP digital signature