[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

LAMBDA syntax counter-proposal



Here is another idea for a more "Lispy" LAMBDA-list syntax that some
people here at CMU came up with.  It is simpler to parse than &-syntax,
but has all the power of &optional, &rest, and &aux.  Moreover, it is
more concise.  It does not extend to other kinds of declaration.

[0] A LAMBDA list is a (possibly dotted) list of specifiers,
    one for each non-rest parameter.
[1] An atomic specifier names a required parameter.
[2] A non-atomic specifier is of the form (<name> <init> <namep>).  The second
    and third items may be omitted.  This describes an optional parameter.
[3] A non-() tail must be a symbol.  It names a rest parameter.
[4] (Optional rule.)  All atomic specifiers must precede all non-atomic ones.
[5] That's all.

&aux variables are handled by the incredibly subtle dodge of using an
embedded PROG or LET.  Other declarations are handled another way, such
as by local DECLARE forms.

Here are some comparative examples of the use of this syntax.

(DEFUN STRING-POSITION (CH STR (START 0) (END (STRING-LENGTH STR)))
  (DO ((J START (+ J 1)))
      ((= J END) ())
    (WHEN (CHAR-EQUAL CH (CHAR STR J)) (RETURN J))))

(DEFUN STRING-POSITION (CH STR &OPTIONAL (START 0) (END (STRING-LENGTH STR)))
  (DO ((J START (+ J 1)))
      ((= J END) ())
    (WHEN (CHAR-EQUAL CH (CHAR STR J)) (RETURN J))))

(DEFUN ASET (NEWVAL ARRAY . SUBSCRIPTS)
  (LET ((N (ARRAY-RANK ARRAY)))
    (DO ((J 0 (+ J 1))
         (S SUBSCRIPTS (CDR S))
         (LIN 0 (+ (* LIN (ARRAY-DIMENSION ARRAY J)) (CAR S))))
        ((= J N)
         (IF (NULL S) (%LINEAR-ASET ARRAY LIN NEWVAL) (TOO-MANY-SUBSCRIPTS)))
      (IF (NULL S) (TOO-FEW-SUBSCRIPTS)))))

(DEFUN ASET (NEWVAL ARRAY &REST SUBSCRIPTS &AUX (N (ARRAY-RANK ARRAY)))
  (DO ((J 0 (+ J 1))
       (S SUBSCRIPTS (CDR S))
       (LIN 0 (+ (* LIN (ARRAY-DIMENSION ARRAY J)) (CAR S))))
      ((= J N)
       (IF (NULL S) (%LINEAR-ASET ARRAY LIN NEWVAL) (TOO-MANY-SUBSCRIPTS)))
    (IF (NULL S) (TOO-FEW-SUBSCRIPTS))))

This representation is very easy to parse, because each LAMBDA-list
element corresponds to exactly one parameter.  It is also always more
concise, with two exceptions.  The word &optional is simply omitted,
and &rest is replaced by a dot.  The word &aux is replaced by "(let ("
and two close parentheses, and so is longer by three printing characters
plus a bit of whitespace (excption #1).  If there are many &optional
parameters all defaulting to (), then "&optional x y z ..." must become
"(x) (y) (z) ..."; this is less concise if there are more than five such
parameters (exception #2).

Omitting optional rule [4] permits optional parameters to precede
required parameters.  This has some limited usefulness:

(DEFUN LOG ((BASE 10) NUM)
  (/ (LN NUM) (LN BASE)))

(LOG 2) => 0.301...		;Log base 10 of 2
(LOG 16 2) => 0.25		;Log base 16 of 2

(DEFUN TURBOPROP (SYM (NEWVAL () NEWP) PROP)	;Can do either GET or PUTPROP
  (IF NEWP (PUTPROP SYM NEWVAL PROP) (GET SYM PROP)))

This idea has been mentioned before, of course.  It has the disadvantage
of requiring two-pass processing when binding parameters to arguments.
I'd be inclined to retain rule [4].
--Guy