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 >: > > > > 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