functionelisp

How to use &key and &rest in a cl-defun togather?


I have a function like this

(cl-defun foo (a b c d e &rest f)
  nil)

Arguments c, d and e are nil 80% of time.

To make it looks better, I do this:

(cl-defun foo (a b &rest f &key c d e &allow-other-keys)
  nil)

When c,d and e are not provided, it's fine.

However, if one of them is used, f gets a wrong argument. For example:

(foo 1 2 :c 6 3 4 5)
;; ==> expected: a=1, b=2, c=6, f= (3 4 5)
;; ==> real case: a=1, b=2, c=6, f= (:c 6 3 4 5) 

Solution

  • The behavior you see is the one specified by CommonLisp (actually I'm not sure if your call (foo 1 2 :c 6 3 4 5) is even valid in Common-Lisp because I think it would treat 3 and 5 as degenerate keywords and the 5 keyword lacks a value).

    IOW the list you get via &rest includes all the keywords. So if you don't want them, you have to drop them by hand (at which point you're often better off not using &key at all).

    Example for removing the keys c d e from the list f:

    (dolist (key '(c d e))
      (cl-remf f key))