2011-11-13 6 views
5

Tôi đang cố gắng viết một hàm Lisp có thể lấy đối số tùy chọn và từ khóa. Hàm bắt đầuLàm cách nào tôi có thể có đối số tùy chọn VÀ đối số từ khóa cho cùng một chức năng?

(defun max-min (v &optional max min &keyword (start 0) (end nil)) 

Khi tôi cố gọi hàm bằng cách sử dụng đối số từ khóa nhưng không phải là đối số từ khóa, tôi gặp lỗi. Những gì tôi đang cố gắng làm là

(max-min #(1 2 3 4) :start 1 :end 2) 

Tôi nhận được lỗi Error: :START' is not of the expected type REAL'

Tôi cho rằng điều này là bởi vì nó đang cố gắng để ràng buộc :start để max. Làm cách nào tôi có thể làm việc này? Cảm ơn.

Trả lời

8

Bạn cần gọi hàm đó với thông số bắt buộc, thông số tùy chọn và sau đó là thông số từ khóa. Nó hoạt động như thế nào? Cuộc gọi của bạn thiếu các thông số tùy chọn. Nếu bạn muốn chỉ định tham số từ khóa trong cuộc gọi, tùy chọn không còn tùy chọn nữa.

(max-min #(1 2 3 4) 0 100 :start 1 :end 2) 

Nguyên tắc phong cách cơ bản:

Không trộn lẫn bắt buộc với các thông số từ khóa trong một hàm. Ví dụ, Lisp thường sử dụng nó ở một nơi nào đó và nó là một nguồn lỗi.

CL:READ-FROM-STRING là ví dụ như vậy.

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

này hoạt động:

(read-from-string " 1 3 5" t nil :start 2) 

này có thể làm việc thêm:

(read-from-string " 1 3 5" :start 2) 

Nhưng người sử dụng quên để xác định EOF-ERROR-P và EOF-GIÁ TRỊ . Trình biên dịch Lisp có thể không phàn nàn và người dùng sẽ tự hỏi tại sao nó sẽ không bắt đầu từ 2.

5

Đối với đầy đủ lợi ích, bạn về mặt kỹ thuật có thể lấy nó để làm việc bằng cách phân tích danh sách các đối số cung cấp cho mình:

(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 
     ;; ... 
     )))) 

Như thường lệ, bạn nên nghe Rainer. Điều này trông giống như một thiết kế quá huyền diệu. Nó làm lẫn lộn cả môi trường phát triển (bằng cách tự động phá vỡ màn hình arglist tự động) và người dùng (bằng cách làm cho các lỗi khó tìm hơn: điều gì sẽ xảy ra khi bạn vô tình truyền một từ khóa mà bạn dự định truyền số?).