How can I have optional arguments AND keyword arguments to the same function?

浪子不回头ぞ 提交于 2020-01-14 09:10:56

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!