On Fri, Feb 21, 2020 at 7:48 PM Lassi Kortela <xxxxxx@lassi.io> wrote:

instead of lambdas, which would make keyword calls easier to optimize.
That strategy makes me a bit uneasy since making keyword lambdas subtly
different from other lambdas makes it a more complicated abstraction,
with potentially more edge cases that cause trouble to some users.

When people use lambda, they intend to produce a procedure object.  A compiler may note that the lambda can't escape and compile it away, but that should be the default.

However, I'm wondering what good lambda/kw actually is, since there is not and cannot be apply/kw, and plain apply forces all the keyword values to the default.  It sort of reminds me of not having generic-function-lambda in CL; what's the point of an anonymous generic function?  Tell me your thoughts on this.  But continuing with lambda/kw present:
 
I had a similar design mentality
of trying to make lambda/kw a drop-in replacement for lambda.

+1 
 
Common Lisp compilers can optimize keyword calls,

But probably not when the procedure-with-keywords is a lambda.
 
(lambda/kw (a b c :key d e f) ...)

The precise naming of :key vs key: vs &key is up for debate.

&key is standard in most Lisps and does not step on native keywords.  

ObDigression:  ISLisp does not require runtime keyword objects to exist, because they are used only as syntactic keywords in various special forms/macros (no explicit distinction in the spec)  and there is a fixed list,  namely :abstractp, :accessor, :after, :around, :before, :boundp, :generic, :initarg, :initform, :metaclass, :method, :reader, :rest, :writer.  However, &rest can be used instead of :rest.

(call/kw proc 1 2 3 :d 4 :e 5 :f 6)

+1
 
* Several Scheme implementations already read :e as a keyword object. 
This means that in practice, when reading random Scheme code from the
internet, :e may already be intended as a keyword object. Hence using :e
as a variable name in a portable Scheme program may be confusing to
people or unreliable across existing Scheme implementations.

Anyone who uses both keyword arguments and normal identifiers that look like keywords deserves to lose.   At least the portable use of keywords is confined to these two macros.
 
* However, no RnRS report has keyword objects yet so standard Scheme
reads :e as an ordinary identifier. It would be nice to preserve this
simplicity in the standard, and add an alternative syntax for keyword
objects. Kawa, Guile and Racket already have #:e.

Getting Scheme implementers to accept new lexical syntax is one of the most difficult things to arrange for, because it often requires pulling apart hand-coded parsers.  CL-style readtables make it straightforward, but only Racket, Gambit, Chicken, and Guile (through Guile-Reader) have them.  So I am very much against this.  Indeed, it is why I have postponed all lexical proposals to the very end of R7RS-large work, and treat any lexical syntax in existing SRFIs as merely advisory until then.
 
* Allowing either ordinary identifiers or keyword objects as keyword
names permits hygienic keywords (which don't yet exist in any known
language, but could be added to Scheme implementations that want them).

IMO the whole point of keywords is that they are not hygienic: they have absolute meaning.  I'm open to being convinced otherwise, of course, but nobody has done even that, still less implemented them.
 
* Since SRFI 177's main goal is compatibility with existing Scheme
keyword systems, it will use the syntax (call/kw foo 1 2 :d 3 :e 4).
Here, :d and :e can be either identifiers (in any Scheme implementation)

Only if it does not automatically treat :d as not an identifier.
 
call/kw would scan for those literal symbols at read time,

At macro expansion time, presumably.
 
* SRFI 177 call/kw would translate all of e: and :e and #:e into the
non-hygienic, global keyword name `e`.
 
Omit "named e", because that suggests it has something to do with a global identifier e and collides with it.

* R7RS-large should probably not use SRFI 177.

On the contrary, I believe that SRFI 177 is the *only* hope of getting keyword arguments into R7RS, politically and logistically.  It's not portable, but it's one of the most portable bits of non-portable code around, thanks to all the work you have put into it.

Not only that, but I want to get it in ASAP so that future SRFIs can define procedures that take keywords.

* default values for keyword arguments

An alternative would be to create a singleton object, use that as the default, and expose a trivial predicate keyword-default-value?.  But #f is probably good enough: Scheme conventionally uses it as a null anyhow.
 
* mixing keyword arguments with positional optional arguments
* mixing keyword arguments with a rest argument

IMO both of these are bogus things to do.  If you add a new optional argument to a CL function, for example, you break all existing calls on that function, because the keyword becomes the value of the new argument and everything else is just wrong after that, but at least you probably get an error.  Add *two* new optional arguments, and the keyword mentioned first just disappears.  CL programmers have to filter out the keyword-value pairs from &rest by hand if they use both.

* allow-other-keys (collecting unknown keywords into a list)

This is the only real nice-to-have that I see from your list, but certainly one can do a lot without it. 
 
Once we decide the final form of SRFI 177, and how to tackle keywords in
R7RS-large, we have a good basis for writing a follow-up SRFI(s) that
allow more complex keyword lambdas to be defined. Perhaps SRFI 89 or
Gauche's syntax is already enough.

Another good thing about SRFI 177 is that it finesses CL-style vs. Racket-style keywords, which I would like to avoid debating if possible.



John Cowan          http://vrici.lojban.org/~cowan        xxxxxx@ccil.org
We do, doodley do, doodley do, doodley do,
What we must, muddily must, muddily must, muddily must;
Muddily do, muddily do, muddily do, muddily do,
Until we bust, bodily bust, bodily bust, bodily bust.  --Bokonon