From: "Marc Nieper-Wißkirchen" <marc@nieper-wisskirchen.de>
To: mhw@netris.org
Cc: guile-devel@gnu.org
Subject: Re: Feature request: Expose `ellipsis?' from psyntax.ss
Date: Sat, 24 Nov 2018 10:08:55 +0100 [thread overview]
Message-ID: <CAEYrNrTBQXDjs5hKTs87Mp=yGUaxzQS0ZD7OFVpkqg8qcpgDYw@mail.gmail.com> (raw)
In-Reply-To: <CAEYrNrTN4vh2qeJ53BTWm4jf+rnbn2+4m+PrKsu_n9r=nECAJA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 7812 bytes --]
Am Fr., 23. Nov. 2018 um 22:28 Uhr schrieb Marc Nieper-Wißkirchen <
marc@nieper-wisskirchen.de>:
> Hi Mark,
>
> Am Fr., 23. Nov. 2018 um 21:26 Uhr schrieb Mark H Weaver <mhw@netris.org>:
>
>> Hi Marc,
>>
>> Marc Nieper-Wißkirchen <marc@nieper-wisskirchen.de> writes:
>>
>> > Am Mi., 21. Nov. 2018 um 04:38 Uhr schrieb Mark H Weaver <
>> mhw@netris.org>:
>> >
>> > I'm not aware of any language in the R[567]RS that makes it clear
>> > whether '...' should be recognized as an ellipsis if it is bound to a
>> > variable. The Scheme implementations I tried do not seem to agree.
>> >
>> > For example, consider this example:
>> >
>> > (let ((... 'hello))
>> > (let-syntax ((foo (syntax-rules ()
>> > ((foo x ...)
>> > '((x) ...)))))
>> > (foo 1 2)))
>> >
>> > If '...' is recognized as an ellipsis within the 'let', then the result
>> > will be '((1) (2)). Otherwise, the result will be '((1) 2).
>> >
>> > I just tested with Chez Scheme 9.5 as well. It returns the same result
>> as Chibi, namely '((1) 2).
>> >
>> > I found that Racket 7.0, Chicken 4.13.0, and Scheme48 1.9.2 return
>> > '((1) (2)). Chibi-Scheme returns '((1) 2). I see the same results
>> > with this variant:
>> >
>> > (let-syntax ((... (syntax-rules ())))
>> > (let-syntax ((foo (syntax-rules ()
>> > ((foo x ...)
>> > '((x) ...)))))
>> > (foo 1 2)))
>> >
>> > Again, Chez returns '((1) 2).
>> >
>> > If we instead bind '...' as a top-level variable:
>> >
>> > (define-syntax ... (syntax-rules ()))
>> > (let-syntax ((foo (syntax-rules ()
>> > ((foo x ...)
>> > '((x) ...)))))
>> > (foo 1 2))
>> >
>> > Then all four of these Schemes agree that the answer is '((1) (2)),
>> > including Chibi-Scheme.
>> >
>> > Chez Scheme still returns '((1) 2) and thus does not recognize `...'
>> > as the ellipsis.
>>
>> I stand by the analysis in my previous response in this thread, but
>> nonetheless I've since realized that given the current implementation of
>> 'ellipsis?' in psyntax.scm, Guile *should* be returning '((1) 2) in
>> these examples above, and I'm not sure why that's not happening.
>>
>> The reason is that when no ellipsis binding is present, Guile currently
>> uses 'free-identifier=?' to compare identifiers with #'(... ...) in
>> psyntax.scm, where '...' has no binding. In the examples above, the
>> ellipsis identifiers are within a lexical environment where '...' is
>> bound, so 'free-identifier=?' should be returning #false in these cases.
>>
>> Having said this, given the analysis in my previous response, I'm now
>> wondering whether it's a mistake to use 'free-identifier=?' to check for
>> the default ellipsis '...'.
>
>
> Using `free-identifier=?' to check for the default ellipsis is definitely
> correct. `bound-identifier=?' would not give the correct results in R[67]RS
> because the ellipsis can be imported under several names. Or use a macro
> that produces aliases of the ellipsis:
>
> (import (scheme base))
>
> (define-syntax foo
> (syntax-rules ()
> ((foo e) TEMPLATE)))
>
> (foo ...)
>
> In TEMPLATE, both `...' and `e' have to be the ellipsis. They are
> `free-identifier=?' but not `bound-identifier=?'.
>
>
>> Within the lexical scope of
>> 'with-ellipsis', Guile uses 'bound-identifier=?' to check for the
>> user-defined ellipsis, but perhaps we should be using it uniformly to
>> check for ellipsis in all cases.
>>
>
> Using `free-identifier=?' would only make sense in a model, in which
> `(with-ellipsis E BODY)' actually binds `E', wouldn't it? In any case,
> inside the scope of `with-ellipsis', the behavior of `syntax-case',
> `syntax' differs substantially with respect to the ellipsis from the
> behavior outside of `with-ellipsis'. Thus it coud very well be that we need
> `bound-identifier=?' in scopes inside `with-ellipsis' and
> `free-identifier=?' in scopes outside.
>
P.S.:
Thought about it a bit more. I think it would work if we used
`free-identifier=?' everywhere, which means: `(with-ellipsis E BODY)'
stores the current binding of `E' in CURRENT-ELLIPSIS-BINDING. In body,
`(ellipsis-identifier? x)' then compares the binding of `x' with
CURRENT-ELLIPSIS-BINDING.
This should be compatible with SRFI-46/R7RS: `(syntax-rules ::: (<id> ---)
<rule> ---)' would be rewritten as `(let-syntax ((::: (auxiliary-syntax)))
(with-ellpsis ::: (syntax-rules (<id> ...) <rule> ---)'.
Does this make sense?
-- Marc
>
>> What do you think?
>>
>> Also, for the sake of completeness I should explain a remaining detail
>> of Guile's semantics for 'with-ellipsis' bindings. In my previous
>> response, I wrote:
>>
>> > I think it makes more sense to model (with-ellipsis E BODY) as
>> > introducing a new lexical binding with a fixed name. CURRENT-ELLIPSIS
>> > would be a good name if we wanted to make it part of the public API.
>> In
>> > this model, 'E' becomes the _value_ of the binding, instead of the
>> > binding's name.
>>
>> In existing versions of Guile, the special fixed name is equivalent to:
>>
>> (datum->syntax E '#{ $sc-ellipsis }#)
>>
>> Where E is the identifier being bound or checked. In particular, the
>> _marks_ from E are copied to the special fixed name, both when binding a
>> new ellipsis identifier and when checking for ellipsis identifier. In
>> other words, for each set of marks there's a distinct ellipsis binding.
>>
>
> That is actually good for hygiene as the following two examples (from an
> earlier post in this thread) show:
>
> So this one indeed outputs #f, thus reproducing your result.
>
> (eval-when (expand)
> (define-syntax bar2
> (syntax-rules ()
> ((_ e body)
> (with-ellipsis e body)))))
>
> (define-syntax foo2
> (lambda (stx)
> (bar2 e (syntax-case stx ()
> ((_a ...)
> #'#t)
> ((_ a b c)
> #'#f)))))
>
> (display (foo2 1 2 3))
> (newline)
>
> On the other hand, this one prints #t.
>
> (eval-when (expand)
> (define-syntax bar2
> (syntax-rules ()
> ((_ e body)
> (with-ellipsis f body))))) ; THE DIFFERENCE IS HERE.
>
> (define-syntax foo2
> (lambda (stx)
> (bar2 e (syntax-case stx ()
> ((_a ...)
> #'#t)
> ((_ a b c)
> #'#f)))))
>
> (display (foo2 1 2 3))
> (newline)
>
>
>
>> WARNING: Note that the name #{ $sc-ellipsis }# is not part of Guile's
>> API, and is subject to change. We reserve the right to change its name,
>> or to make it completely inaccessible in future versions of Guile.
>
>
> I think this would be a good move. Internal names shouldn't be forgeable
> by user code. One may think that no one would name their identifiers `{#
> $sc-ellipsis }#', but these kind of issues can and do happen in
> meta-compiling, code reflection, etc.
>
>
>> For example, we might move the ellipsis bindings out of the substitution
>> and
>> into a separate field in the wrap which maps marks to ellipsis
>> identifiers, with no name involved at all.
>>
>
> Such an approach could be generalized to an API that allows to attach
> custom properties to a lexical scope.
>
>
>> I welcome input on these questions.
>>
>
> Anytime, although I should mention that I am not an expert.
>
> -- Marc
>
>
--
Prof. Dr. Marc Nieper-Wißkirchen
Universität Augsburg
Institut für Mathematik
Universitätsstraße 14
86159 Augsburg
Tel: 0821/598-2146
Fax: 0821/598-2090
E-Mail: marc.nieper-wisskirchen@math.uni-augsburg.de
Web: www.math.uni-augsburg.de/alg/mitarbeiter/mnieper/
[-- Attachment #2: Type: text/html, Size: 16381 bytes --]
prev parent reply other threads:[~2018-11-24 9:08 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-14 13:16 Feature request: Expose `ellipsis?' from psyntax.ss Marc Nieper-Wißkirchen
2018-11-14 19:10 ` Mark H Weaver
2018-11-14 20:27 ` Marc Nieper-Wißkirchen
2018-11-15 9:38 ` Mark H Weaver
2018-11-15 10:03 ` Marc Nieper-Wißkirchen
2018-11-15 10:59 ` Mark H Weaver
2018-11-15 19:41 ` Marc Nieper-Wißkirchen
2018-11-16 0:00 ` Mark H Weaver
2018-11-16 13:37 ` Marc Nieper-Wißkirchen
2018-11-16 23:36 ` Mark H Weaver
2018-11-17 15:03 ` Marc Nieper-Wißkirchen
2018-11-21 3:37 ` Mark H Weaver
2018-11-21 8:40 ` Marc Nieper-Wißkirchen
2018-11-21 16:09 ` Marc Nieper-Wißkirchen
2018-11-23 7:55 ` Mark H Weaver
2018-11-23 21:06 ` Marc Nieper-Wißkirchen
2018-11-23 20:25 ` Mark H Weaver
2018-11-23 21:28 ` Marc Nieper-Wißkirchen
2018-11-24 9:08 ` Marc Nieper-Wißkirchen [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAEYrNrTBQXDjs5hKTs87Mp=yGUaxzQS0ZD7OFVpkqg8qcpgDYw@mail.gmail.com' \
--to=marc@nieper-wisskirchen.de \
--cc=guile-devel@gnu.org \
--cc=mhw@netris.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).