问题
I am trying to write a Lisp function that can take optional and keyword arguments. The function begins
(defun max-min (v &optional max min &keyword (start 0) (end nil))
When I try to call the function using the keyword arguments but not the optional ones, I get an error. What I'm trying to do is
(max-min #(1 2 3 4) :start 1 :end 2)
I'm getting the error Error: :START' is not of the expected type REAL'
I assume that this is because it is trying to bind :start
to max
. How can I get this to work? Thanks.
回答1:
You need to call that function with the required parameter, the optional parameters and then the keyword parameters. How should it work otherwise? Your call lacks the optional parameters. If you want to specify keyword parameters in the call, the optional are no longer optional.
(max-min #(1 2 3 4) 0 100 :start 1 :end 2)
The basic style rule:
Don't mix optional with keyword parameters in a function. Common Lisp for example uses it in some place and it is a source of bugs.
CL:READ-FROM-STRING
is such an example.
read-from-string string
&optional eof-error-p eof-value
&key start end preserve-whitespace
http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_fro.htm
This works:
(read-from-string " 1 3 5" t nil :start 2)
This may work also:
(read-from-string " 1 3 5" :start 2)
But the user forgot to specify the EOF-ERROR-P and EOF-VALUE. The Lisp compiler may not complain and the user will wonder why it won't start at 2.
回答2:
For completeness' sake, you can technically get it to work by parsing the list of supplied arguments yourself:
(defun max-min (v &rest args)
(flet ((consume-arg-unless-keyword (default)
(if (keywordp (first args))
default
(pop args))))
(let ((max (consume-arg-unless-keyword nil))
(min (consume-arg-unless-keyword nil)))
(destructuring-bind (&key (start 0) (end nil)) args
;; ...
))))
As usual, though, it's a good idea to listen to Rainer. This looks like too magical a design. It confuses both the development environment (by breaking automatic arglist display, for instance) and the user (by making type errors harder to find: what happens when you accidentally pass a keyword where you intended to pass a number?).
来源:https://stackoverflow.com/questions/8109274/how-can-i-have-optional-arguments-and-keyword-arguments-to-the-same-function