Here's an example of how you might do what you want to do. This is fairly simple-minded, but it allows you to define functions which take any number of arguments, together with zero or more keyword arguments. There is then a little trampoline which pulls keywords and their values out of the arguments and calls the function appropriately.
This is not meant to be production-quality code: it would clearly be better to have the trampoline-making function know exactly what keywords it was looking for for instance, which could be known, rather than just 'any keywords'.
(defun make-kw-trampoline (fn)
;; Given a function which takes a single rest arg and a bunch of
;; keyword args, return a function which will extract the keywords
;; from a big rest list and call it appropriately
(lambda (&rest args)
(loop for (arg . rest) on args
if (keywordp arg)
if (not (null rest))
collect arg into kws and collect (first rest) into kws
else do (error "Unpaired keyword ~S" arg)
finally (return (apply fn args kws)))))
(defmacro defun/rest/kw (name (rest-arg and-key . kw-specs) &body decls-and-forms)
;; Define a function which can take any number of arguments and zero
;; or more keyword arguments.
(unless (eql and-key '&key)
(error "um"))
(multiple-value-bind (decls forms) (loop for (thing . rest) on decls-and-forms
while (and (consp thing)
(eql (first thing) 'declare))
collect thing into decls
finally (return
(values decls (cons thing rest))))
`(progn
(setf (fdefinition ',name)
(make-kw-trampoline (lambda (,rest-arg &key ,@kw-specs)
,@decls
(block ,name
,@forms))))
',name)))
So if I now define a function like this:
(defun/rest/kw foo (args &key (x 1 xp))
(declare (optimize debug))
(values args x xp))
Then I can call it so:
> (foo 1 2 3)
(1 2 3)
1
t
> (foo 1 2 :x 4 3)
(1 2 :x 4 3)
4
t
Note that defun/rest/kw may not do the same thing that defun does: in particular I think it does enough to define the function properly (and not to define it at compile time) but the compiler may not realise the function exists at compile time (so there may be warnings), and it also does not do any implementation-specific magic.