william.newman@... (William Harold Newman) writes:
> To me, the ANSI specification of LET seems to assume that duplicate
> name binding is nonsense. It doesn't explicitly forbid it, but neither
> does it bother to think about what takes precedence when duplicate
> names are used; this would be a serious oversight if duplicate names
> were intended. I don't think it's much of a stretch instead to
> interpret "binding in parallel" to mean that duplicate names are
> nonsense, more or less as in casual mathematical conversation: we
> don't say "let x be the square root of height, y be the square root of
> area, and x be the cube root of height." The way that different CL
> implementations resolve the precedence in different ways is further
> evidence that we won't be doing the portability-minded user a favor by
> silently accepting the input.
I have come to agree with this in principle. The only thing I need to
come to terms with is why an error is more appropriate than a warning.
> Beyond positional arguments, though, it gets more complicated. By the
> usual analogy between LET and function calls, it would be simple to
> say that *all* function arguments are bound in parallel.
I think of LAMBDA as being more general than a LET in that the former
can emulate the latter. So instead of saying the parallel binding of
LET should determin the processing of LAMBDA parameters, ideally I would
prefer LAMBDA semantics to determine that of LET.
> Unfortunately, &AUX arguments seem to be intended not to be bound in
> parallel, and it is very common (and as useful) to initforms for
> &OPTIONAL and &KEY arguments which refer to the bindings of earlier
&AUX parameters are specifically noted as not being `true' parameters,
and are subject to a different processing rules than other paramters.
> My best guess at the moment is that:
> * LET should signal an error on duplicate names.
> * Lambda list positional arguments should act like LET arguments,
> while lambda list arguments which accept initforms should act
> like LET* arguments nested inside the LET, so
> (DEFUN FROB (V W X &OPTIONAL (Y (SQRT X)) &KEY (Z (SQRT Y)))
> behaves rather like
> (LET ((V ...) (W ...) (X ...))
> (LET* ((Y ...) (Z ...))
> * Whether or not &KEY arguments allow binding the same variable
> name more than once, it is probably an error to use duplicate
> From that point of view it's probably not an error to do something
> (DEFUN FROB (X &OPTIONAL X &KEY X) ...),
> strange though that is; but it probably is an error to do
> (DEFUN FROB (X &OPTIONAL X &KEY X X) ...)
> or just
> (DEFUN FROB (&KEY X X) ...).
I dont like defining LAMBDA in terms of LET. LAMBDA is better defined.
For the sake of argument, lets drop the notion of `duplicate
parameters'. All we have are plain parameters, processed from left to
right, where I read `processed' to include the act of binding. This
is, I belive, compliant with the standard. So then
(DEFUN FROB (X &OPTIONAL X &KEY X X) X)
is well defined. It always returns NIL except when a key pair for :X
> I don't like (DEFUN FROB (X &OPTIONAL X &KEY X) ...), though, and if I
> were writing the spec I'd explicitly forbid it, so if someone finds a
> place where it's explicitly forbidden, I'll be happy.
I dont like it either, and I would thrash the user with a stern
warning. But I really dont think this is undefined.