Am Di., 3. März 2020 um 12:22 Uhr schrieb Lassi Kortela <xxxxxx@lassi.io>:
> The lambda/kw (keyword-lambda in the old draft) macro, however,
> interprets the keywords both as symbols and as identifiers. They are
> interpreted as symbols when the keyword list passed by call/kw is
> examined, but they are interpreted as identifiers when they are bound
> through let in the body of the procedure taking keyword arguments.
>
> Without macro expansions, symbols and identifiers can be used
> interchangeably. With, however, there is a difference. Symbols are
> compared by `eq?', identifiers in let binding forms are compared by
> `bound-identifier=?'. In general, both equivalence predicates are not
> comparable.
>
> Thus, in the most general contexts where lambda/kw can be used, there
> can be a problem. There will also at least be an inconvenience if a
> keyword argument is named in a way that would shadow an identifier used
> in the body of the procedure.
>
> The simple solution is to slightly extend the system so that, for example,
>
> (lambda/kw (a b (c d (f e))))
>
> would mean to bind the identifier c to the keyword argument named c, the
> identifier d to the keyword argument named d, and the identifier f to
> the keyword argument e.

Excellent observation. This didn't occur to me. Your in-depth knowledge
of macro systems is really useful to the community :)

If the distinction between symbols and identifiers is important, it
shouldn't be a problem to add a syntax like the one you propose. Since
it's an optional feature that is not used most of the time, it doesn't
cause any disruption.

I'd probably like to omit it from 177 on grounds of simplicity, but from
my limited understanding it sounds like it makes sense to have it in a
full-blown language spec like R7RS-large. If we can find a simple way to
add it to 177 as well, it's still possible too.

Aside from the macro expansion issue, users may really ask about a way to choose identifiers that do no necessarily have the same name as the keyword symbols.

For example, consider some procedure that constructs its result using CONS. You may later want to add some optional keyword argument called `cons', so that the user can explicitly specify the constructor used, e.g. `ipair' from SRFI 116.

In the body of that procedure, you don't want to shadow the cons binding.

Example:

(define CONS cons) ; ?!

(define/kw (map proc lst (cons))
  (let ((cons (or cons CONS)))
    (fold-right (lambda (x res) (cons (proc x) res)) '() lst)))

The line marked with "?!" shouldn't be made necessary.
What do you mean by "If we can find a simple way to add it to ..."? Is there a hard way?

BTW, the above is another example where keyword arguments makes a lot sense together with rest arguments:

(map proc lst1 lst2 lst3 lst4 cons: ipair)

looks perfectly sane. (The syntax is not set in stone, of course.)

Marc

177 has to be implementable using non-hygienic define-macro as well, but
this issue shouldn't prevent that.


--
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: xxxxxx@math.uni-augsburg.de
Web: www.math.uni-augsburg.de/alg/mitarbeiter/mnieper/