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 : > >> Hi Marc, >> >> Marc Nieper-Wißkirchen 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 ::: ( ---) ---)' would be rewritten as `(let-syntax ((::: (auxiliary-syntax))) (with-ellpsis ::: (syntax-rules ( ...) ---)'. 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/