add something like plt's syntax-local-value

Bug #225387 reported by Stephen Wrobleski
2
Affects Status Importance Assigned to Milestone
Ikarus Scheme
Fix Committed
Wishlist
Abdulaziz Ghuloum

Bug Description

Basically, I'd like to grab the value associated with a syntax binding

; mzscheme example

(define-syntax print-syntax-value
  (lambda (stx)
    (syntax-case stx ()
      ((_ id)
       (identifier? #'id)
       (begin
         (display (syntax-local-value #'id))
         (newline)
         #'(begin))))))

(define-syntax vv 42)

; displays 42 during expansion phase
(print-syntax-value vv)

This feature would allow macro-controlled expansion of subexpressions, and extensible macros using syntactical keywords.

Ikarus restricts syntax bindings to procedures, which is less than ideal, but this can be worked around by wrapping arbitrary values in a lambda. (Omitted in the example for clarity)

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote : Re: [Bug 225387] [NEW] add something like plt's syntax-local-value

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:
> Basically, I'd like to grab the value associated with a syntax binding
>
> ; mzscheme example
>
> (define-syntax print-syntax-value
> (lambda (stx)
> (syntax-case stx ()
> ((_ id)
> (identifier? #'id)
> (begin
> (display (syntax-local-value #'id))
> (newline)
> #'(begin))))))
>
> (define-syntax vv 42)
>
> ; displays 42 during expansion phase
> (print-syntax-value vv)

Does this only work at the top-level?

 > (let ([x 3])
     (print-syntax-value x)
     12)
syntax-local-value: not defined as syntax: #<syntax::298>
  === context ===
/Applications/PLT Scheme v3.99.0.18/collects/scheme/private/misc.ss:68:7

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote :

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:
> (define-syntax vv 42)

Sorry, missed that. I thought that was (define vv 42).

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote :

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:
> This feature would allow macro-controlled expansion of subexpressions,
> and extensible macros using syntactical keywords.

Can you provide an example of each of these two things that you're
trying
to do?

Revision history for this message
Stephen Wrobleski (mindslight) wrote :

It looks like my email reply to <email address hidden> didn't make it here even though I didn't get an error.

Explicit expansion is the obvious case of something you can't do under r6rs
(+ikarus) that would be enabled

; "expands" the outer level of the given expression
; 1. assumes the first element is a syntactical keyword
; 2. does not deal with expansions of the other elements, nested forms, or a
; new returned syntax form

(define (expand-outer stx)
  (syntax-case stx ()
    [(id etc ...)
     ((syntax-local-value #'id) stx)]))

Fixing the restrictions in the example would create a full-functional explicit
expansion mechanism. Such explicit subexpansion would be necessary to
implement functionality similar to the local defines of let and lambda.

(define-syntax define-five
  (syntax-rules (define-five)
    [(define-five id)
     (define id 5)]))

; evaluates to 5
(let ()
  (define-five vv)
  vv)

a user-defined 'let' can only know what to do with define-five after it
explicitly expands and sees that it's a define clause (rather than an
expression)

Imagine a 'class' syntax definition, which uses two keywords 'method' and
'field'. The keywords are defined to raise an error, and the 'class' expander
does a free-identifier=? to test for their usage.

To be able to create a new definition on top of that library (without touching the
library itself), the class macro must explicitly pre-expand forms so that it
can check for returned method and field forms.

There are cases where I would like to be able to check for the presence of a
syntactical definition rather than blindly expanding, which is why I see
syntax-local-value as more useful than a generic expand.

..

For the case of arbitrary values being passed around at expansion time as
syntactical keywords, think of the r6rs syntactic record layer. When
defining a record, a syntactical definition is created for the 'type', which
is used by further macros to influence the code they generate. I'd like that
generalized capability to use in my own code.

...

When not transforming, syntax-local-value errors out (as there is no
transformer environment to look in)

When called on kernel syntax (like #'if), syntax-local-value also errors
out, as it is not a syntax transformer.

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote : Re: [Bug 225387] Re: add something like plt's syntax-local-value
Download full text (4.2 KiB)

On May 6, 2008, at 3:13 AM, Stephen Wrobleski wrote:
> It looks like my email reply to <email address hidden> didn't
> make it
> here even though I didn't get an error.
>
> Explicit expansion is the obvious case of something you can't do
> under r6rs
> (+ikarus) that would be enabled
>
> ; "expands" the outer level of the given expression
> ; 1. assumes the first element is a syntactical keyword
> ; 2. does not deal with expansions of the other elements, nested
> forms, or a
> ; new returned syntax form
>
> (define (expand-outer stx)
> (syntax-case stx ()
> [(id etc ...)
> ((syntax-local-value #'id) stx)]))

This will not work in general for all keyword-bound identifiers
for two reasons:

1. You are collapsing two macro expansion steps into one. This
will cause incorrect (and often insidious) hygiene problems in
the mark/antimark algorithm.

2. Not all syntaxes are bound to procedures so you cannot just
call the value.

> Fixing the restrictions in the example would create a full-
> functional explicit
> expansion mechanism. Such explicit subexpansion would be necessary to
> implement functionality similar to the local defines of let and
> lambda.
>
> (define-syntax define-five
> (syntax-rules (define-five)
> [(define-five id)
> (define id 5)]))
>
> ; evaluates to 5
> (let ()
> (define-five vv)
> vv)
>
> a user-defined 'let' can only know what to do with define-five
> after it
> explicitly expands and sees that it's a define clause (rather than an
> expression)

Hmmm. I'm not sure I understand here.

A user-define let in terms of lambda would not have to know about
define-five. Just try it:

 > (let-syntax ([let
                 (syntax-rules ()
                   [(_ ([x v] ...) b b* ...)
                    ((lambda (x ...) b b* ...) v ...)])])
     (let ()
       (define-syntax define-five
         (syntax-rules ()
           [(_ id) (define id 5)]))
       (define-five vv)
       vv))
5

If what you want is actually implement full internal defines, that
would require me to expose all of the expander's internals and you
would have to know how to handle each and every form the expander
may throw at you. Neither you nor I would want to do this. Since
lambda already has an internal defines context in its body, you can
just use that.

> Imagine a 'class' syntax definition, which uses two keywords
> 'method' and
> 'field'. The keywords are defined to raise an error, and the
> 'class' expander
> does a free-identifier=? to test for their usage.

Like quasiquote recognizing unquote and unquote-splicing (each of
which raises a syntax error), right?

> To be able to create a new definition on top of that library
> (without touching the
> library itself), the class macro must explicitly pre-expand forms
> so that it
> can check for returned method and field forms.

Well, that's not how I'd do it. I'd just let it fail and the
syntax error trace would show the original offender.

> There are cases where I would like to be able to check for the
> presence of a
> syntactical definition rather than blindly expanding, which is why
> I see
> syntax-local-value as more useful than a generic expan...

Read more...

Revision history for this message
Abdulaziz Ghuloum (aghuloum) wrote :

Added the ability to add compile time values in revision 1677. (I know it's too late, sorry)

Changed in ikarus:
assignee: nobody → aghuloum
importance: Undecided → Wishlist
status: New → Fix Committed
Changed in ikarus:
milestone: none → 0.0.4
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.