unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Macro for replacing a placeholder in an expression
@ 2022-07-27 23:57 Zelphir Kaltstahl
  2022-07-28  0:55 ` Maxime Devos
  2022-07-28  1:04 ` Maxime Devos
  0 siblings, 2 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-27 23:57 UTC (permalink / raw)
  To: Guile User

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




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-27 23:57 Macro for replacing a placeholder in an expression Zelphir Kaltstahl
@ 2022-07-28  0:55 ` Maxime Devos
  2022-07-28 10:23   ` Zelphir Kaltstahl
  2022-07-28  1:04 ` Maxime Devos
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-07-28  0:55 UTC (permalink / raw)
  To: Zelphir Kaltstahl, Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 1274 bytes --]

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.


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-27 23:57 Macro for replacing a placeholder in an expression Zelphir Kaltstahl
  2022-07-28  0:55 ` Maxime Devos
@ 2022-07-28  1:04 ` Maxime Devos
  2022-07-28  8:39   ` Zelphir Kaltstahl
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-07-28  1:04 UTC (permalink / raw)
  To: guile-user


[-- Attachment #1.1.1: Type: text/plain, Size: 2148 bytes --]


On 28-07-2022 01:57, Zelphir Kaltstahl wrote:
> 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. 

Here's what happening:

(test (lambda (a) (+ a 1))

--> because  the 'test' in the beginning is a macro

((test lambda) (test (a)) (test (+ a 1))

--> likewise

(lambda (test (a)) (test (+ a 1))

Now we end up with the 'lambda' macro. The lambda macro sees as argument 
list (test (a)) and interprets 'test' as the first argument, but the 
second part '(a)' is not an identifier so the lambda macro cannot do 
anything with that and tells you that by saying: lambda: invalid 
argument list in ....

This seems the same issue as in 'Re: boiler plate class generation, 
writing fresh variables with macros' to me but in a slightly different 
context

> Syntax transformations in Scheme work from the outside to the inside, 
> not the other way around, so you can't do things like this 
> (define-class doesn't know what to do with this 'slot-machine' thing, 
> it will reject it for not being a valid slot definition). However, you 
> can define a syntax that generates the surrounding define-class and 
> interprets things to insert the result of slot-matchine into a proper 
> define-class form. 
I consider a (in your case recursive, but in that case more like 
something like syntax-map (which can be defined recursively in terms of 
syntax-case)) syntax-case to be practical for this (more so than pure 
syntax-rules), see my other response.

Greetings,
Maxime


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-28  1:04 ` Maxime Devos
@ 2022-07-28  8:39   ` Zelphir Kaltstahl
  2022-07-28  9:48     ` Maxime Devos
  0 siblings, 1 reply; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-28  8:39 UTC (permalink / raw)
  To: Maxime Devos; +Cc: Guile User

Hello Maxime!

Thank you for your quick response! (Mailing list saves me again! Yay!)

On 7/28/22 03:04, Maxime Devos wrote:
>
> On 28-07-2022 01:57, Zelphir Kaltstahl wrote:
>> 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. 
>
> Here's what happening:
>
> (test (lambda (a) (+ a 1))
>
> --> because  the 'test' in the beginning is a macro
>
> ((test lambda) (test (a)) (test (+ a 1))
>
> --> likewise
>
> (lambda (test (a)) (test (+ a 1))
>
> Now we end up with the 'lambda' macro. The lambda macro sees as argument list 
> (test (a)) and interprets 'test' as the first argument, but the second part 
> '(a)' is not an identifier so the lambda macro cannot do anything with that 
> and tells you that by saying: lambda: invalid argument list in ....

Ahhh now I get it! lambda is also a macro … I did not think of that.


>
> This seems the same issue as in 'Re: boiler plate class generation, writing 
> fresh variables with macros' to me but in a slightly different context
>
>> Syntax transformations in Scheme work from the outside to the inside, not the 
>> other way around, so you can't do things like this (define-class doesn't know 
>> what to do with this 'slot-machine' thing, it will reject it for not being a 
>> valid slot definition). However, you can define a syntax that generates the 
>> surrounding define-class and interprets things to insert the result of 
>> slot-matchine into a proper define-class form. 

And this explains the order of expansion! Something I've already been wondering 
about, what the order is or what the rules are.


> I consider a (in your case recursive, but in that case more like something 
> like syntax-map (which can be defined recursively in terms of syntax-case)) 
> syntax-case to be practical for this (more so than pure syntax-rules), see my 
> other response.

I aimed to do everything with syntax-rules, as the simplest means, but when 
writing the code I have, I hit the snag, that one could not have multiple 
ellipses at the same level of nesting in the patterns. After some thinking I 
found the solution to build up a temporary list, which then is of course 1 
deeper level of nesting, where I could then use ellipses again. I felt quite 
clever doing that trick. Maybe I could implement a syntax-map using that trick 
and then use syntax-map in my macro instead.

I have a question regarding syntax-case:

If I use it, does my code become less portable to other Schemes?

And regarding syntax-rules:

How portable are macros, which exclusively use syntax-rules?

>
> Greetings,
> Maxime

Thank you again for your help and explanations! Things are much clearer now!

Best regards,
Zelphir

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




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-28  8:39   ` Zelphir Kaltstahl
@ 2022-07-28  9:48     ` Maxime Devos
  2022-07-28 11:26       ` Zelphir Kaltstahl
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-07-28  9:48 UTC (permalink / raw)
  To: Zelphir Kaltstahl; +Cc: Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 2113 bytes --]


On 28-07-2022 10:39, Zelphir Kaltstahl wrote:
> I aimed to do everything with syntax-rules, as the simplest means, but 
> when writing the code I have, I hit the snag, that one could not have 
> multiple ellipses at the same level of nesting in the patterns.

IIUC, you mean:

(syntax-rules ()
   ((foo x ... y ...) [the replacement]))

? If so, such a construct is ambigious.

> After some thinking I found the solution to build up a temporary list, 
> which then is of course 1 deeper level of nesting, where I could then 
> use ellipses again. I felt quite clever doing that trick. Maybe I 
> could implement a syntax-map using that trick and then use syntax-map 
> in my macro instead. 
> I have a question regarding syntax-case:
>
> If I use it, does my code become less portable to other Schemes?
>
> And regarding syntax-rules:
>
> How portable are macros, which exclusively use syntax-rules?
>
Everything that supports syntax-case most likely supports syntax-rules 
too, as syntax-rules can easily be defined in terms of syntax-case, so 
syntax-rules is at least as portable as syntax-case.

syntax-rules and syntax-case are pretty standard (it's in the R6RS), so 
I expect them to be available in recent-ish non-minimalistic Schemes.

However, some Schemes (likely Schemes that predate the R6RS, or in 
Schemes that try new things out), use other syntax systems.

Anyway, I've found a table:

> https://docs.scheme.org/surveys/syntax-definitions/

Looks like syntax-rules is supported by all the tested systems. 
syntax-case is less supported, but among the 'low-level' macro systems 
it has the highest support.  It's a bit out-of-date though, syntax-case 
is supported for Chicken: 
http://code.call-cc.org/legacy-eggs/3/syntax-case.html,

Decide for yourself of course, but I don't think going for maximal 
portability is worth the effort here of something making things work 
with syntax-rules.

>>
>> Greetings,
>> Maxime
>
> Thank you again for your help and explanations! Things are much 
> clearer now!
>
> Best regards,
> Zelphir 


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-28  0:55 ` Maxime Devos
@ 2022-07-28 10:23   ` Zelphir Kaltstahl
  2022-07-28 10:28     ` Maxime Devos
  2022-07-30 15:42     ` Zelphir Kaltstahl
  0 siblings, 2 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-28 10:23 UTC (permalink / raw)
  To: Maxime Devos; +Cc: Guile User

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

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


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-28 10:23   ` Zelphir Kaltstahl
@ 2022-07-28 10:28     ` Maxime Devos
  2022-07-30 15:42     ` Zelphir Kaltstahl
  1 sibling, 0 replies; 14+ messages in thread
From: Maxime Devos @ 2022-07-28 10:28 UTC (permalink / raw)
  To: Zelphir Kaltstahl; +Cc: Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 309 bytes --]


On 28-07-2022 12:23, Zelphir Kaltstahl wrote:
> I'll need to look at this and learn about eval-when

The eval-when is only required if the macro is 'run' when the module 
holding the macro is compiled (to avoid some compilation failures); 
often the eval-when can be dropped.

Greetings,
Maxime.


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-28  9:48     ` Maxime Devos
@ 2022-07-28 11:26       ` Zelphir Kaltstahl
  0 siblings, 0 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-28 11:26 UTC (permalink / raw)
  To: Maxime Devos; +Cc: Guile User

On 7/28/22 11:48, Maxime Devos wrote:
>
>
> On 28-07-2022 10:39, Zelphir Kaltstahl wrote:
>> I aimed to do everything with syntax-rules, as the simplest means, but when 
>> writing the code I have, I hit the snag, that one could not have multiple 
>> ellipses at the same level of nesting in the patterns.
>
> IIUC, you mean:
>
> (syntax-rules ()
>   ((foo x ... y ...) [the replacement]))
>
> ? If so, such a construct is ambigious.
>
Yep, that is the case I meant : )


>> After some thinking I found the solution to build up a temporary list, which 
>> then is of course 1 deeper level of nesting, where I could then use ellipses 
>> again. I felt quite clever doing that trick. Maybe I could implement a 
>> syntax-map using that trick and then use syntax-map in my macro instead. 
>> I have a question regarding syntax-case:
>>
>> If I use it, does my code become less portable to other Schemes?
>>
>> And regarding syntax-rules:
>>
>> How portable are macros, which exclusively use syntax-rules?
>>
> Everything that supports syntax-case most likely supports syntax-rules too, as 
> syntax-rules can easily be defined in terms of syntax-case, so syntax-rules is 
> at least as portable as syntax-case.
>
> syntax-rules and syntax-case are pretty standard (it's in the R6RS), so I 
> expect them to be available in recent-ish non-minimalistic Schemes.
>
> However, some Schemes (likely Schemes that predate the R6RS, or in Schemes 
> that try new things out), use other syntax systems.
>
> Anyway, I've found a table:
>
>> https://docs.scheme.org/surveys/syntax-definitions/
>
> Looks like syntax-rules is supported by all the tested systems. syntax-case is 
> less supported, but among the 'low-level' macro systems it has the highest 
> support.  It's a bit out-of-date though, syntax-case is supported for Chicken: 
> http://code.call-cc.org/legacy-eggs/3/syntax-case.html,
>
> Decide for yourself of course, but I don't think going for maximal portability 
> is worth the effort here of something making things work with syntax-rules.
>
Hm OK, thanks for that! Well, it is in a repository of guile-examples, so I 
guess I can let go of wanting to do it all with syntax-rules.


>>>
>>> Greetings,
>>> Maxime
>>
>> Thank you again for your help and explanations! Things are much clearer now!
>>
>> Best regards,
>> Zelphir 

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


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  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:13       ` Maxime Devos
  1 sibling, 2 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-30 15:42 UTC (permalink / raw)
  To: Maxime Devos; +Cc: Guile User

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: #<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. 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 is impossible? To expand to subforms being 
the same macro again and this way transform a whole tree of s-expressions?

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

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.

Best regards,
Zelphir

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


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  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
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-07-30 20:44 UTC (permalink / raw)
  To: Zelphir Kaltstahl; +Cc: Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 4775 bytes --]


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.

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-30 20:44       ` Maxime Devos
@ 2022-07-30 21:10         ` Maxime Devos
  0 siblings, 0 replies; 14+ messages in thread
From: Maxime Devos @ 2022-07-30 21:10 UTC (permalink / raw)
  To: Zelphir Kaltstahl; +Cc: Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 548 bytes --]


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 [...]

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-30 15:42     ` Zelphir Kaltstahl
  2022-07-30 20:44       ` Maxime Devos
@ 2022-07-30 21:13       ` Maxime Devos
  2022-08-05  9:42         ` Linus Björnstam
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-07-30 21:13 UTC (permalink / raw)
  To: Zelphir Kaltstahl; +Cc: Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 504 bytes --]


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 
<https://git.gnunet.org/gnunet-scheme.git/tree/gnu/gnunet/utils/hat-let.scm>.

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

Greetings,
Maxime.


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-07-30 21:13       ` Maxime Devos
@ 2022-08-05  9:42         ` Linus Björnstam
  2022-08-06 14:28           ` Zelphir Kaltstahl
  0 siblings, 1 reply; 14+ messages in thread
From: Linus Björnstam @ 2022-08-05  9:42 UTC (permalink / raw)
  To: Maxime Devos, Zelphir Kaltstahl; +Cc: Guile User

I wrote this, which does a tree fold over a sexp:

https://hg.sr.ht/~bjoli/megacut/browse/readme.txt?rev=tip

It is unhygienic currently, and I will probably never change because I only use it at the repl. 

The code is really just a syntax-case version of the fast and efficient flatten algorithm, but without flattening. 

-- 
  Linus Björnstam

On Sat, 30 Jul 2022, at 23:13, Maxime Devos wrote:
> 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 
> <https://git.gnunet.org/gnunet-scheme.git/tree/gnu/gnunet/utils/hat-let.scm>.
>
> However, I do not see a way to implement recursivity the same way for 
> your macro.
>
> Greetings,
> Maxime.
>
>
> Attachments:
> * OpenPGP_0x49E3EE22191725EE.asc
> * OpenPGP_signature



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Macro for replacing a placeholder in an expression
  2022-08-05  9:42         ` Linus Björnstam
@ 2022-08-06 14:28           ` Zelphir Kaltstahl
  0 siblings, 0 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-08-06 14:28 UTC (permalink / raw)
  To: Linus Björnstam; +Cc: Guile User, Maxime Devos

Hello Linus!

On 8/5/22 11:42, Linus Björnstam wrote:
> I wrote this, which does a tree fold over a sexp:
>
> https://hg.sr.ht/~bjoli/megacut/browse/readme.txt?rev=tip
>
> It is unhygienic currently, and I will probably never change because I only use it at the repl.
>
> The code is really just a syntax-case version of the fast and efficient flatten algorithm, but without flattening.

I might study it later. Thank you for that. I have found a solution to my previous problems of expansion order using CK macros described at: https://okmij.org/ftp/Scheme/macros.html#ck-macros.

Everything seems to work now, except some cases with vectors, I think only with vector syntax #(...). That is what I am still trying to figure out. However, the current code is in my repository of Guile examples. I would (perma-)link to it, but currently notabug has an issue.

Using CK macros does make the macros simpler, although one must get the quoting right, which is sometimes confusing.

Best regards,
Zelphir

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




^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-08-06 14:28 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-27 23:57 Macro for replacing a placeholder in an expression Zelphir Kaltstahl
2022-07-28  0:55 ` 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

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