Suggested set of new keyword SRFIs Lassi Kortela 17 Jul 2020 10:53 UTC
Suggested new SRFIs:
1. An extremely simple one specifying a (call/key foo 1 2 3 :d 4 :e 5
:f 6) macro to call keyword procedures from portable code without
using keyword objects. The macro turns :foo and foo: identifiers
into keyword objects (where available) and into quoted symbols
2. Another extremely simple one specifying a #!keywords reader flag to
parse both :foo and foo: as SRFI 88 keyword objects. Or perhaps a
separate reader flag for each.
3. One giving a way to define simple keyword procedures using global
(i.e. non-hygienic) keywords with #f default values, pass them
around freely, and call them.
(lambda/key (a b c &key d e f) ...)
(define/key (foo a b c &key d e f) ...)
lambda/key expands into a lambda using native keyword arguments and
keyword objects where available. Otherwise the kw args are passed
in a rest argument parsed as a plist, with symbols for keywords.
define/key is allowed to expand the identifier syntax `foo` into a
lambda and to separately expand the list syntax `(foo ...)` into an
optimized / statically checked call.
In all of these cases, (foo 1 2 3 :c 4 :d 5 :e 6) or (foo 1 2 3 c:
4 d: 5 e: 6) or (foo 1 2 3 #:c 4 #:d 5 #:e 6) can be used naturally
provided that the implementation has that keyword read syntax. If
not, we can import the `call/key` hack SRFI and use it.
(I suggest `/key` instead of `/kw` for symmetry with &key or :key or
#!key in the lambda list, and because with the above proposal,
call/key can be omitted in most calls.)
The above three SRFIs should cover most practical use cases for the
near future. I can write or co-write them.
Additionally, advanced SRFIs can be written later. I'd prefer that
other people write them.
- non-#f default values for keyword arguments
- required keyword arguments (as in Racket)
- mixing keyword arguments with optional positional arguments
- mixing keyword arguments with a rest argument
- hygienic keywords
- binding the keyword argument to a differently-named variable inside
the procedure body (e.g. the call `(foo :bar 1)` binds 1 to a
variable called `qux` inside `foo`, not to a variable called `bar`).