unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
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: Fri, 23 Nov 2018 22:28:41 +0100	[thread overview]
Message-ID: <CAEYrNrTN4vh2qeJ53BTWm4jf+rnbn2+4m+PrKsu_n9r=nECAJA@mail.gmail.com> (raw)
In-Reply-To: <87a7lzpmly.fsf@netris.org>

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

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.


> 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

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

  reply	other threads:[~2018-11-23 21:28 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 [this message]
2018-11-24  9:08                             ` Marc Nieper-Wißkirchen

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='CAEYrNrTN4vh2qeJ53BTWm4jf+rnbn2+4m+PrKsu_n9r=nECAJA@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).