unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Lexically bound macro, with lexically bound transformer
@ 2024-07-24  1:06 spacecadet
  2024-07-24 11:15 ` Taylan Kammer
  0 siblings, 1 reply; 7+ messages in thread
From: spacecadet @ 2024-07-24  1:06 UTC (permalink / raw)
  To: guile-devel

Hi, I didn't see a help-guile list, I hope this isn't out of place

I'm trying to lexically bind a macro to a lexically bound transformer procedure

(let ((outer (lambda (x) #''())))
   (let-syntax ((inner outer))
     inner))

This is producing an error
"reference to identifier outside its scope in form outer"

My goal is to load external macros without any top-level definitions
I don't know if the way the macro expander works will allow this
Any help appreciated, thanks!



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

* Re: Lexically bound macro, with lexically bound transformer
  2024-07-24  1:06 Lexically bound macro, with lexically bound transformer spacecadet
@ 2024-07-24 11:15 ` Taylan Kammer
  2024-07-24 17:10   ` spacecadet
  0 siblings, 1 reply; 7+ messages in thread
From: Taylan Kammer @ 2024-07-24 11:15 UTC (permalink / raw)
  To: spacecadet, guile-devel

On 24.07.2024 03:06, spacecadet wrote:
> Hi, I didn't see a help-guile list, I hope this isn't out of place

I think the guile-user list might be more appropriate.

> I'm trying to lexically bind a macro to a lexically bound transformer procedure
> 
> (let ((outer (lambda (x) #''())))
>   (let-syntax ((inner outer))
>     inner))
> 
> This is producing an error
> "reference to identifier outside its scope in form outer"
> 
> My goal is to load external macros without any top-level definitions
> I don't know if the way the macro expander works will allow this
> Any help appreciated, thanks!

Scheme evaluation could be considered to happen in two parts, regardless of whether the implementation actually has a compiler:

1. The compile-time execution of code

2. The run-time execution of code

(Guile actually has a compiler so it's definitely like this in practice too.)

The 'let' form works in the context of run-time execution, whereas 'let-syntax' works in compile-time execution. Although compile-time code can "see" that a variable called 'outer' is bound in the lexical scope, the actual value of the binding will only exist at run-time, so you can't rely on it during compile-time execution.

The following works:

  (let-syntax ((outer (lambda (x) #'(+ 1 2))))
    (let-syntax ((inner (lambda (x) (outer x))))
      (inner)))

The 'inner' has to be a lambda too, and can't be bound to 'outer' directly. I'm not sure why.

-- 
Taylan




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

* Re: Lexically bound macro, with lexically bound transformer
  2024-07-24 11:15 ` Taylan Kammer
@ 2024-07-24 17:10   ` spacecadet
  2024-07-24 19:54     ` Attila Lendvai
                       ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: spacecadet @ 2024-07-24 17:10 UTC (permalink / raw)
  To: Taylan Kammer, guile-devel

> I think the guile-user list might be more appropriate.

Noted

>    (let-syntax ((outer (lambda (x) #'(+ 1 2))))
>      (let-syntax ((inner (lambda (x) (outer x))))
>        (inner)))

That works, but I guess this isn't possible then

(lambda* (#:key outer)
   (let-syntax ((inner outer))
     (inner ...)))

Since that would require evaluating run-time code at compile-time

Is there a way to write a macro that's expanded at run-time?

It feels like I'm asking the wrong question now, but I'm
really looking for a way to bind macros at run-time
so they can be used functionally

I guess the right answer is to use functions instead of macros?



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

* Re: Lexically bound macro, with lexically bound transformer
  2024-07-24 17:10   ` spacecadet
@ 2024-07-24 19:54     ` Attila Lendvai
  2024-07-25  9:50     ` Taylan Kammer
  2024-07-26  7:56     ` Maxime Devos
  2 siblings, 0 replies; 7+ messages in thread
From: Attila Lendvai @ 2024-07-24 19:54 UTC (permalink / raw)
  To: spacecadet; +Cc: Taylan Kammer, guile-devel

> I guess the right answer is to use functions instead of macros?

if you're not sure about the answer, then it's most probably yes.

-- 
• attila lendvai
• PGP: 963F 5D5F 45C7 DFCD 0A39
--
“The only way to deal with an unfree world is to become so absolutely free that your very existence is an act of rebellion.”
	— Albert Camus (1913–1960)




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

* Re: Lexically bound macro, with lexically bound transformer
  2024-07-24 17:10   ` spacecadet
  2024-07-24 19:54     ` Attila Lendvai
@ 2024-07-25  9:50     ` Taylan Kammer
  2024-07-26  7:56     ` Maxime Devos
  2 siblings, 0 replies; 7+ messages in thread
From: Taylan Kammer @ 2024-07-25  9:50 UTC (permalink / raw)
  To: spacecadet, guile-devel

On 24.07.2024 19:10, spacecadet wrote:
>> I think the guile-user list might be more appropriate.
> 
> Noted
> 
>>    (let-syntax ((outer (lambda (x) #'(+ 1 2))))
>>      (let-syntax ((inner (lambda (x) (outer x))))
>>        (inner)))
> 
> That works, but I guess this isn't possible then
> 
> (lambda* (#:key outer)
>   (let-syntax ((inner outer))
>     (inner ...)))
> 
> Since that would require evaluating run-time code at compile-time
> 
> Is there a way to write a macro that's expanded at run-time?
> 
> It feels like I'm asking the wrong question now, but I'm
> really looking for a way to bind macros at run-time
> so they can be used functionally
> 
> I guess the right answer is to use functions instead of macros?

Yeah, it's generally a good idea to reserve macros for things that regular procedures (functions) simply can't do.

Many things where one thinks of using a macro can be done using a higher-order functions instead. (I.e. a procedure that takes another procedure as an argument and executes it in some special context.)

For example, let's say I want a way to time (benchmark) code. I could create a macro to do it like this:

;; Example code only, may not work properly

(define-syntax time
  (syntax-rules ()
    ((_ body ...)
     (let ((start-time (current-time)))
       body ...
       (- (current-time) start-time)))))

(time
 (do-thing)
 (do-other-thing)
 (very-complicated-thing))

Or I could just use a higher-order function:

(define (time thunk)
  (let ((start-time (current-time)))
    (thunk)
    (- (current-time) start-time)))

(time
  (lambda ()
    (do-thing)
    (do-other-thing)
    (very-complicated-thing)))

-- 
Taylan




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

* RE: Lexically bound macro, with lexically bound transformer
  2024-07-24 17:10   ` spacecadet
  2024-07-24 19:54     ` Attila Lendvai
  2024-07-25  9:50     ` Taylan Kammer
@ 2024-07-26  7:56     ` Maxime Devos
  2024-07-27  0:30       ` spacecadet
  2 siblings, 1 reply; 7+ messages in thread
From: Maxime Devos @ 2024-07-26  7:56 UTC (permalink / raw)
  To: spacecadet, Taylan Kammer, guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1247 bytes --]



Sent from Mail for Windows

From: spacecadet
Sent: Wednesday, 24 July 2024 19:11
To: Taylan Kammer; guile-devel@gnu.org
Subject: Re: Lexically bound macro, with lexically bound transformer

> I think the guile-user list might be more appropriate.

Noted

>    (let-syntax ((outer (lambda (x) #'(+ 1 2))))
>      (let-syntax ((inner (lambda (x) (outer x))))
>        (inner)))

That works, but I guess this isn't possible then

(lambda* (#:key outer)
   (let-syntax ((inner outer))
     (inner ...)))

Since that would require evaluating run-time code at compile-time

>Is there a way to write a macro that's expanded at run-time?

With (local-eval #'(insert expression to be done at run-time) (the-environment)), yes.
Caveat (from manual):

>Note that the current implementation of (the-environment) only captures “normal” lexical bindings, and pattern variables bound by syntax-case. It does not currently capture local syntax transformers bound by let-syntax, letrec-syntax or non-top-level define-syntax forms. Any attempt to reference such captured syntactic keywords via local-eval or local-compile produces an error.

The question is: why would you do that?

Best regards,
Maxime  Devos

[-- Attachment #2: Type: text/html, Size: 4927 bytes --]

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

* Re: Lexically bound macro, with lexically bound transformer
  2024-07-26  7:56     ` Maxime Devos
@ 2024-07-27  0:30       ` spacecadet
  0 siblings, 0 replies; 7+ messages in thread
From: spacecadet @ 2024-07-27  0:30 UTC (permalink / raw)
  To: Maxime Devos, Taylan Kammer, guile-devel@gnu.org

> The question is: why would you do that?

Why not? :)

I'm trying to create a functional module system (similar to nixpkgs/nixos),
where modules are functions, imports are arguments, and exports are just the
return of the function.

Seems like scheme macros can't really work like that, although the suggestions
have given me a lot of help. Thank you.



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

end of thread, other threads:[~2024-07-27  0:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-24  1:06 Lexically bound macro, with lexically bound transformer spacecadet
2024-07-24 11:15 ` Taylan Kammer
2024-07-24 17:10   ` spacecadet
2024-07-24 19:54     ` Attila Lendvai
2024-07-25  9:50     ` Taylan Kammer
2024-07-26  7:56     ` Maxime Devos
2024-07-27  0:30       ` spacecadet

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