Hi Mark, Am Fr., 23. Nov. 2018 um 08:56 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 >: > > > > > Ellipsis identifiers are a bit more tricky, because unlike other > > > bindings, the user-visible ellipsis identifiers are not actually > > > substituted. We can't do that because ellipsis identifiers can be > used > > > for other purposes, e.g. bound to ordinary variables or macros, and > > > these two ways of binding ellipsis identifiers should not shadow each > > > other. > > Sorry, this was a weak argument. I've since remembered the _actual_ > reason that it needs to be done this way: > > In general, for any sensible binding form, bindings with different names > should not shadow each other. For example, a binding for 'E' should not > shadow a binding for 'F'. > > If you try to model (with-ellipsis E BODY) as binding 'E', then it is > not a sensible binding form in this sense. Unlike any sensible binding > form, (with-ellipsis E BODY) should not only shadow outer bindings of > 'E', but *any* outer ellipsis binding, whether '...' or 'F' or something > else. In other words, in this model, there can be only one binding of > this kind in a given lexical context. > Alternatively, it would be enough for all use cases that come to my mind if `(with-ellipsis E BODY)' besides binding `E' would shadow `...' and nothing else. E.g. under this alternative semantics, in the BODY of `(with-ellipsis E (with-ellipsis F BODY))' both `E' and `F' would function as ellipses, while `...' would not. In other case, `with-ellipsis' would work like the following macro transformer: (lambda (stx) (syntax-case stx () ((k e body) (with-syntax ((::: (datum->syntax k '...))) #'(let-syntax ((::: ) (e )) body))))) This way, `with-ellipsis' would behave more like an ordinary (albeit unhygienic) binding construct. Therefore, I think this is a bad model for 'with-ellipsis'. > > 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. > > Does that make sense? > So CURRENT-ELLIPSIS would be the name of an identifier whose name is disjoint to all names a user could use for their identifiers? Or would you model CURRENT-ELLIPSIS as a parameter object, which would entail a different semantics? > Note that in this later model, it's not natural for (with-ellipsis E > BODY) to shadow a binding for 'E' or vice versa, because 'E' is not > actually the thing being bound by 'with-ellipsis'. > > In theory, we could introduce additional mechanisms to force > (with-ellipsis E BODY) to shadow bindings for 'E' and vice versa. This > would entail changing *every* binding form to check if the identifier > being bound matches the current binding of CURRENT-ELLIPSIS, and if so, > somehow invalidating the ellipsis binding. It's not obvious what should > be done in this case. > > We could do something like this, but in my view, it would be an ad-hoc > addition to the semantics in order to support the inadequate mental > model where (with-ellipsis E BODY) is thought of as binding 'E'. > > What do you think? > I agree with you that trying to shadow bindings for `E' in a model in which `with-ellipsis' does not actually bind `E' but some other identifier is the opposite of being beautiful. So I don't think one should try to do this in this model. We have, however, the semantics of R[67]RS, where `...' has an actual binding as auxiliary syntax. This allows to have more than one identifier acting as the ellipsis at the same time (just import `...' from `(scheme base)' or `(rnrs base)' under two different names). Whatever model for `with-ellipsis' is chosen, it should work well with `R[67]RS'. It just comes to my mind that this rules out my model from above (the syntax transformer that rebinds `...'). :-) So, here may be a better model: Each lexical scope has a flag ORIGINAL-ELLIPSIS?. In the top-level scope, the flag is set. As long as the flag is set, `syntax-case' and `syntax' check for the ellipsis by using `free-identifier=?' and comparing with the binding for `...' as exported by `(rnrs base)'. Now, `(with-syntax e BODY)' clears this flag in BODY and binds `e' to a special ellipsis value. Alternatively, in the model where `with-ellipsis' should not bind anything, `ORIGINAL-ELLIPSIS?' becomes your `CURRENT-ELLIPSIS'. As long as it is unset, `syntax-case' and `syntax' check for the ellipsis by using `free-identifier=?' as above. When `CURRENT-ELLIPSIS' is bound to `e', the checking is done with `(bound-identifier=? e ---)'. -- Marc