Am Fr., 23. Nov. 2018 um 22:28 Uhr schrieb Marc Nieper-Wißkirchen <
m...@nieper-wisskirchen.de>:

> Hi Mark,
>
> Am Fr., 23. Nov. 2018 um 21:26 Uhr schrieb Mark H Weaver <m...@netris.org>:
>
>> Hi Marc,
>>
>> Marc Nieper-Wißkirchen <m...@nieper-wisskirchen.de> writes:
>>
>> > Am Mi., 21. Nov. 2018 um 04:38 Uhr schrieb Mark H Weaver <
>> m...@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-wisskirc...@math.uni-augsburg.de
Web: www.math.uni-augsburg.de/alg/mitarbeiter/mnieper/

Reply via email to